Convertir l'anglais en un nombre [fermé]


27

Description courte et douce du défi:

Sur la base des idées de plusieurs autres questions sur ce site, votre défi est d'écrire le code le plus créatif dans n'importe quel programme qui prend en entrée un nombre écrit en anglais et le convertit en forme entière.

Spécifications vraiment sèches, longues et approfondies:

  • Votre programme recevra en entrée un entier en anglais minuscule entre zeroet nine hundred ninety-nine thousand nine hundred ninety-nineinclus.
  • Il doit sortir uniquement la forme entière du nombre entre 0et 999999et rien d'autre (pas d'espace blanc).
  • L'entrée ne contiendra PAS, ou and, comme dans one thousand, two hundredou five hundred and thirty-two.
  • Lorsque les dizaines et les emplacements sont tous deux non nuls et que l'emplacement des dizaines est supérieur à 1, ils seront séparés par un caractère HYPHEN-MOINS -au lieu d'un espace. Idem pour les dix mille et mille lieux. Par exemple six hundred fifty-four thousand three hundred twenty-one,.
  • Le programme peut avoir un comportement indéfini pour toute autre entrée.

Quelques exemples d'un programme bien comporté:

zero-> 0
fifteen-> 15
ninety-> 90
seven hundred four-> 704
sixty-nine thousand four hundred eleven-> 69411
five hundred twenty thousand two->520002


Ce n'est pas particulièrement créatif, ni ne correspond précisément à la spécification ici, mais cela pourrait être utile comme point de départ: github.com/ghewgill/text2num/blob/master/text2num.py
Greg Hewgill

Je pourrais presque poster ma réponse à cette question .
grc

Pourquoi faire une analyse de chaîne compliquée? pastebin.com/WyXevnxb
blutorange

1
Au fait, j'ai vu une entrée de l'IOCCC qui est la réponse à cette question.
Snack

2
Qu'en est-il des choses comme "vingt-quatre?"
moelleux

Réponses:


93

Applescript

Un mash-up stupide et hacky qui pourrait bouleverser certaines personnes de Cupertino / Mountain View, mais je pense que c'est un mash-up créatif idiot et hacky.

set myNumber to text returned of (display dialog ¬
    "Enter number as text:" buttons {"Continue…"} ¬
    default answer "" default button 1)
tell application "Google Chrome"
    activate
    open location "https://www.google.com"
end tell
delay 5
say "ok google. " & myNumber
delay 2
tell application "System Events"
    tell application process "Google Chrome"
        set fullURL to value of text field 1 of toolbar 1 of window 1
    end tell
end tell
set AppleScript's text item delimiters to "="
display alert item 2 of text items of fullURL

Utilise la synthèse vocale OSX pour prononcer le numéro de texte et la recherche audio Google pour l'écouter et le convertir en entier.

Exigences

  • OSX
  • Google Chrome
  • reconnaissance vocale activée dans votre compte google
  • le volume est monté à un niveau raisonnable

Les délais de retard peuvent devoir être ajustés en fonction de votre temps de chargement Chrome et de votre temps de recherche Google.

Exemple d'entrée:

entrez la description de l'image ici

Exemple de sortie:

entrez la description de l'image ici


13
Je pense que cela pourrait être juste un peu créatif ...;)
Abraham

5
Lol, c'est cool
juste la moitié du

2
Peut-être trop créatif.
Cheezey

Après une semaine, votre réponse est clairement en tête avec 74 votes, donc je pense que cela signifie que .. vous gagnez! Au fait, ça vous dérange si j'utilise ce code? Ce serait vraiment utile pour beaucoup de projets du monde réel sur lesquels je travaille en ce moment! ;)
Abraham

3
@Abraham Merci! Vous plaisantez sur l'utilisation de cela dans le code de production, non?
Digital Trauma

34

Bash, 93 64 55 caractères *

Dans le fantastique bsd-gamespackage disponible sur la plupart des systèmes d'exploitation Linux, il y a un petit jouet en ligne de commande appelé number. Il transforme les nombres en texte anglais, c'est-à-dire qu'il fait exactement le contraire de cette question. C'est exactement le contraire: toutes les règles de la question sont suivies number. C'est presque trop beau pour être une coïncidence.

$ number 42
forty-two.

Bien sûr, numberne répond pas à la question. Nous voulons l'inverse. J'ai réfléchi à cela pendant un certain temps, essayé l'analyse de chaînes et tout cela, puis réalisé que je pouvais simplement appeler numbertous les numéros 999.999 et voir si quelque chose correspond à l'entrée. Si c'est le cas, la première ligne où elle correspond a le double du numéro de ligne que je recherche ( numberimprime une ligne de points après chaque numéro). Aussi simple que cela. Alors, sans plus tarder, voici le code complet de mon entrée:

seq 0 999999|number -l|awk "/$1/{print (NR-1)/2;exit}"

Il court-circule même, donc la conversion de "deux" est assez rapide, et des nombres encore plus élevés sont généralement décodés en moins d'une seconde sur ma box. Voici un exemple d'exécution:

wn@box /tmp> bash unnumber.sh "zero"
0
wn@box /tmp> bash unnumber.sh "fifteen"
15
wn@box /tmp> bash unnumber.sh "ninety" 
90
wn@box /tmp> bash unnumber.sh "seven hundred four"
704
wn@box /tmp> bash unnumber.sh "sixty-nine thousand four hundred eleven"
69411
wn@box /tmp> bash unnumber.sh "five hundred twenty thousand two"    
520002

Bien sûr, vous devrez avoir numberinstallé pour que cela fonctionne.


*: Oui, je sais, ce n'est pas un code-golfdéfi, mais la brièveté est à peu près la seule qualité discernante de mon entrée, alors ... :)


8
+1. Pour moi, utiliser numberà l'envers est la chose la plus créative de cette réponse. Le golf est également bon :)
Digital Trauma

1
C'est en fait assez créatif! Je l'aime!
sokie

13

Javascript

(function parse(input) {
  var pat = "ze/on/tw/th.?r/fo/fi/ix/se/ei/ni/ten/ele".split("/");
  var num = "", last = 0, token = input.replace(/-/g, " ").split(" ");
  for(var i in token) {
    var t = token[i];
    for(var p in pat) if(t.match(RegExp(pat[p])) !== null) num += "+" + p;
    if(t.indexOf("een") >= 0) num += "+10";
    if(t.indexOf("lve") >= 0) num += "+10";
    if(t.indexOf("ty") >= 0) num += "*10";
    if(t.indexOf("dr") >= 0) { last = 100; num += "*100"; }
    if(t.indexOf("us") >= 0) {
      if(last < 1000) num = "(" + num + ")"; last = 0;
      num += "*1000";
    }
  }
  alert(eval(num));
})(prompt());

Vous en aimez eval()?

Exécutez ce script sur la console de votre navigateur.

Edit: Merci pour les commentaires. Bugs corrigés (encore).


code vraiment sympa ^^
zsitro

2
Lorsque vous tapez quelque chose comme "cent seize", cela donne 126.
scrblnrd3

Ce programme échoue pour certains numéros à partir de twelveson retour 23.
Abraham

Échoue "twenty".
200_success

seven thousand three hundred thirty fivedonne moi10335
Baby

7

Python

Juste pour faire rouler la balle.

import re
table = {'zero':0,'one':1,'two':2,'three':3,'four':4,'five':5,'six':6,'seven':7,'eight':8,'nine':9,
         'ten':10,'eleven':11,'twelve':12,'thirteen':13,'fourteen':14,'fifteen':15,'sixteen':16,'seventeen':17,'eighteen':18,'nineteen':19,
         'twenty':20,'thirty':30,'forty':40,'fifty':50,'sixty':60,'ninety':90}
modifier = {'hundred':100,'thousand':1000}

while True:
    text = raw_input()
    result = 0
    tmp = 0
    last_multiplier = 1
    for word in re.split('[- ]', text):
        multiplier = modifier.get(word, 1)
        if multiplier > last_multiplier:
            result = (result+tmp)*multiplier
            tmp = 0
        else:
            tmp *= multiplier
        if multiplier != 1:
            last_multiplier = multiplier
        tmp += table.get(word,0)
    print result+tmp

5

Perl + CPAN

Pourquoi réinventer la roue alors qu'elle est déjà terminée?

use feature 'say';
use Lingua::EN::Words2Nums;

say words2nums $_ while <>;

Ce programme lit les chaînes anglaises à partir de l'entrée standard (ou d'un ou plusieurs fichiers spécifiés comme arguments de ligne de commande), une par ligne, et imprime les nombres correspondants sur la sortie standard.

J'ai testé ce code en utilisant à la fois les exemples d'entrées du défi, ainsi qu'une suite de tests exhaustive composée des nombres de 0 à 999999 convertis en texte à l'aide de l' numberutilitaire bsd-games (merci, Wander Nauta!), Et il analyse correctement tous. En prime, il comprend également des entrées telles que minus seven(−7), four and twenty(24), four score and seven(87), one gross(144), a baker's dozen(13), eleventy-one(111) et googol(10 100 ).

( Remarque: En plus de l'interpréteur Perl lui-même, ce programme nécessite également le module CPAN Lingua :: EN :: Words2Nums . Voici quelques instructions pour installer les modules CPAN . Les utilisateurs de Debian / Ubuntu Linux peuvent également installer ce module via le gestionnaire de paquets APT comme liblingua-en-words2nums-perl .)


4

Python

Une solution récursive générale, avec contrôle de validité. Pourrait être simplifié pour la plage de nombres requise, mais voici à montrer, je suppose:

terms = 'zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen'.split()
tee  = 'twenty thirty forty fifty sixty seventy eighty ninety'.split()
for t in tee:
    terms.append(t)
    for s in terms[1:10]:
        terms.append(t+'-'+s)

terms = dict(zip(terms, range(100)))

modifiers = [('hundred', 100), ('thousand', 1000), ('million', 10**6), ('billion', 10**9)]

def read_num(words):
    if len(words) == 0: return 0
    elif len(words) == 1:
        if words[0] in terms:
            return terms[words[0]]
        else:
            raise ValueError(words[0]+' is not a valid english number.')
    else:
        for word, value in reversed(modifiers):
            if word in words:
                i = words.index(word)
                return read_num(words[:i])*value+read_num(words[i+1:])

    raise ValueError(' '.join(words)+' is not a valid english number.')

while True:
    try:
        print(read_num(input().split()))
    except ValueError as e:
        print(e)

2

VBScript 474

C'est une réponse assez routinière ... malheureusement, tellement routinière que @Snack a à peu près affiché le même processus mais avant moi.

i=split(REPLACE(REPLACE(inputbox(""),"lve","een"),"tho","k"))
o=split("z on tw th fo fi si se ei ni ten ele")
y=split("red *100) k )*1000 ty *10) een +10)")
z=""
p=0
for t=0 to UBOUND(i)
    s=split(i(t),"-")
    u=ubound(s)
    r=s(0)
    for x=0 to UBOUND(o)    
        IF INSTR(r,o(x)) THEN
            z=z+"+"+CSTR(x)
        END IF
        IF u Then
            IF INSTR(s(1),o(x)) THEN
                z=z+CSTR(x)
            END IF
        END IF
    next
    for m=0 to UBOUND(y)
        IF INSTR(r,y(m))AND u=0 THEN
            z=z+y(m+1)
            p=p+1
        END IF
    next
next
Execute("MSGBOX "+String(p,"(")+z)

1

Haskell

Semblable à d'autres solutions récursives je suppose, mais j'ai pris le temps de le nettoyer.

Voici la source complète avec toutes les explications: http://ideone.com/fc8zcB

-- Define a type for a parser from a list of tokens to the value they represent.
type NParse = [Token] -> Int    

-- Map of literal tokens (0-9, 11-19 and tens) to their names.
literals = [
        ("zero", 0), ("one", 1), ("two", 2), ("three", 3), ("four", 4), ("five", 5), ("six", 6), ("seven", 7), ("eight", 8), ("nine", 9),
        ("eleven", 11), ("twelve", 12), ("thirteen", 13), ("fourteen", 14), ("fifteen", 15), ("sixteen", 16), ("seventeen", 17), ("eighteen", 18), ("nineteen", 19),
        ("ten", 10), ("twenty", 20), ("thirty", 30), ("fourty", 40), ("fifty", 50), ("sixty", 60), ("seventy", 70), ("eighty", 80), ("ninety", 90)
    ]

-- Splits the input string into tokens.
-- We do one special transformation: replace dshes by a new token. Such that "fifty-three" becomes "fifty tens three". 
prepare :: String -> [Token]

-- Let's do the easy stuff and just parse literals first. We just have to look them up in the literals map.
-- This is our base parser.
parseL :: NParse
parseL [tok] = case lookup tok literals of 
    Just x -> x

-- We're going to exploit the fact that the input strings have a tree-like structure like so
--                    thousand
--          hundred             hundred
--      ten       ten       ten         ten
--    lit   lit lit  lit   lit  lit    lit  lit
-- And recursively parse that tree until we only have literal values.
--
-- When parsing the tree
--       thousand
--     h1       h2
-- The resulting value is 1000 * h1 + h2.
-- And this works similarly for all levels of the tree.
-- So instead of writing specific parsers for all levels, let's just write a generic one :

{- genParse :: 
    NParse      : the sub parser
    -> Int      : the left part multiplier
    -> Token    : the boundary token 
    -> NParse   : returns a new parser -}   
genParse :: NParse -> Int -> Token -> NParse    
genParse delegate mul tok = newParser where
    newParser [] = 0
    newParser str = case splitAround str tok of
        -- Split around the boundary token, sub-parse the left and right parts, and combine them
        (l,r) -> (delegate l) * mul + (delegate r)  

-- And so here's the result: 
parseNumber :: String -> Int
parseNumber = parseM . prepare
    where   -- Here are all intermediary parsers for each level
    parseT = genParse   parseL  1       "tens"       -- multiplier is irregular, because the fifty in fifty-three is already multiplied by 10
    parseH = genParse   parseT  100     "hundred"
    parseK = genParse   parseH  1000    "thousand"
    parseM = genParse   parseK  1000000 "million" -- For fun :D

test = (parseNumber "five hundred twenty-three thousand six hundred twelve million two thousand one") == 523612002001

0

Lisp commun, 94

(write(cdr(assoc(read-line)(loop for i to 999999 collect(cons(format()"~r"i)i)):test #'equalp)))

La conversion de nombre en texte est intégrée à CL, mais pas l'inverse. Construit un mappage inverse pour les nombres et vérifie l'entrée sur celui-ci.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.