Conversion d'entiers en mots anglais

21

Le but de ce code golf est de convertir des entiers en mots anglais.

Le programme vous invite à entrer. Si cette entrée n'est pas un entier, imprimez NaN. S'il s'agit d'un entier, convertissez-le en mots anglais et imprimez ces mots. Entrée minimale: 0 (zéro). Entrée maximale: 9000 (neuf mille).
Donc, 5retourne five(la casse n'a pas d'importance) et 500retourne five hundredou five-hundred(les tirets n'ont pas d'importance).

Quelques autres règles:

Un oneavant hundredou thousandest facultatif: one hundredest correct, mais hundredaussi (si l'entrée est 100bien sûr).

Le mot anddans par exemple one hundred and forty fiveest facultative aussi.

L'espace est important. Donc, pour 500, five-hundredou five hundredc'est correct, mais ce fivehundredn'est pas le cas.

Bonne chance!

ProgramFOX
la source
Il y a une réponse non golfée ici rgagnon.com/javadetails/java-0426.html .
Cette réponse dans SO fait des choses similaires mais n'est pas du code-golf.
ST3

Réponses:

7

Perl 281 octets

print+0eq($_=<>)?Zero:"@{[((@0=($z,One,Two,Three,Four,Five,@2=(Six,Seven),
Eight,Nine,Ten,Eleven,Twelve,map$_.teen,Thir,Four,@1=(Fif,@2,Eigh,Nine)))
[$_/1e3],Thousand)x($_>999),($0[($_%=1e3)/100],Hundred)x($_>99),
($_%=100)>19?((Twen,Thir,For,@1)[$_/10-2].ty,$0[$_%10]):$0[$_]]}"||NaN

Ajout de nouvelles lignes pour la santé mentale horizontale. Ce qui précède peut être utilisé de manière interactive ou en lui attribuant une valeur via stdin.

Fonctionne correctement pour toutes les valeurs entières sur la plage [0, 19999] , les valeurs en dehors de cette plage présentent un comportement non défini. Les valeurs non entières seront tronquées vers zéro, et en tant que telles, seules les valeurs réellement non numériques seront signalées NaN.

Exemple d'utilisation:

for $n (14, 42, 762, 2000, 6012, 19791, 1e9, foobar, 17.2, -3) {
  print "$n: ", `echo $n | perl spoken-numbers.pl`, $/;
}

Exemple de sortie:

14: Fourteen
42: Forty Two
762: Seven Hundred Sixty Two
2000: Two Thousand 
6012: Six Thousand Twelve
19791: Nineteen Thousand Seven Hundred Ninety One
1000000000: Thousand 
foobar: NaN
17.2: Seventeen
-3: Nine Hundred Ninety Seven
primo
la source
"1000000000: Mille"? Et 17.2 ne devrait-il pas imprimer "NaN"?
DavidC
5
@DavidCarraher "... les valeurs en dehors de cette plage présentent un comportement indéfini . Les valeurs non entières seront tronquées vers zéro, et en tant que telles, seules les valeurs qui ne sont vraiment pas numériques seront signalées NaN."
primo
Je ne suis pas un expert Perl, donc je pose cette question: ce programme demande-t-il une entrée?
ProgramFOX
@ProgramFOX Je l'ai mis à jour pour lire une valeur depuis stdin (s'il est exécuté de manière interactive, il demandera à l'utilisateur une valeur), plutôt qu'en tant que fonction.
primo
13

JavaScript (375)

Probablement une tentative terrible, mais de toute façon, c'est parti ...

alert(function N(s,z){return O="zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,,fif,,,eigh,,,,twen,,for".split(","),(z?O[s]||O[s-10]||O[s-20]:s<13?N(s,1):s<20?N(s,1)+"teen":s<100?N(a=20+(s/10|0),1)+"ty"+(s%10?" "+N(s%10):""):s<1e3?N(s/100|0)+" hundred"+(s%100?" "+N(s%100):""):s<1e5?N(s/1e3|0)+" thousand"+(s%1e3?" "+N(s%1e3):""):0)||NaN}(prompt()))

Assez imprimé (en fonction):

function N(s,z) {
  return O = "zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,,fif,,,eigh,,,,twen,,for".split(","),
      (z? O[s] || O[s-10] || O[s-20]
       : s < 13?  N(s,1)
       : s < 20?  N(s,1) + "teen"
       : s < 100? N(a=20+(s/10|0),1) + "ty" + (s%10?" "+N(s%10):"")
       : s < 1e3?  N(s/100|0) +  " hundred" + (s%100?" "+N(s%100):"")
       : s < 1e5?  N(s/1e3|0) + " thousand" + (s%1e3?" "+N(s%1e3):"") : 0) || NaN
}

Exemple de conversion (notez qu'il sort même NaNen dehors des limites, c'est-à-dire une entrée invalide):

540: five hundred forty
4711: four thousand seven hundred eleven
7382: seven thousand three hundred eighty two
1992: one thousand nine hundred ninety two
hutenosa: NaN
1000000000: NaN
-3: NaN
Luciole
la source
+1il est assez difficile de faire mieux dans une langue comme javascript. (vous pouvez supprimer l'espace N(s,z) {returnpour enregistrer 1 caractère)
Math chiller
Oh, haha, ça a dû manquer. Il me semble également avoir raté un tas de caractères dans la Ochaîne. Je vais arranger ça ..
FireFly
11

Mathematica 60 57

f = ToString@#~WolframAlpha~{{"NumberName", 1}, "Plaintext"} &

Usage:

f[500]

cinq cents

Éditer:

InputString[]~WolframAlpha~{{"NumberName", 1}, "Plaintext"}
alephalpha
la source
3
Cela ne répond pas vraiment à la question. J'ai dit que l'utilisateur devait entrer un nombre (en utilisant la ligne de commande ou une boîte de dialogue par exemple), puis votre programme devrait sortir les mots (sur la ligne de commande ou dans une boîte de message par exemple). Votre code est juste une fonction pour le convertir, et votre programme ne demande pas d'entrée.
ProgramFOX
@ProgramFOX, il dit «L'utilisateur entre quelque chose». Cela ne signifie pas «Le programme vous invite à entrer».
MrZander
@MrZander: Eh bien, "Le programme invite à entrer" était en fait ce que je voulais dire. Je mets à jour ma question, mais bien sûr, il serait injuste que je ne vote pas la réponse d'alephalpha, alors il a obtenu mon +1
ProgramFOX
8

Lisp, 72 56 caractères

Je me rends compte 1) que c'est ancien et 2) qu'il repose entièrement sur la bibliothèque standard pour fonctionner, mais le fait que vous puissiez faire en sorte que le système d'impression c-lisp fasse ce genre de chose m'a toujours impressionné. En outre, cela prend en fait l'entrée d'un utilisateur, la convertit et l'imprime.

(format t "~:[NaN~;~:*~r~]" (parse-integer (read-line) :junk-allowed t))

Il totalise 72 caractères.

  • :junk-allowed fait en sorte que parse-integer renvoie nil en cas d'échec au lieu de déclencher une erreur.
  • ~:[if-nil~;if-non-nill] conditionnelle basée sur zéro, gère NaN si nécessaire
  • ~:* sauvegarde l'interprétation des arguments pour consommer à nouveau l'entrée
  • ~r imprime le nombre sous forme de chaîne de mots anglais, comme demandé, sauf avec une ponctuation entièrement corrigée

Échantillon:

17823658
seventeen million, eight hundred and twenty-three thousand, six hundred and fifty-eight

192hqfwoelkqhwef9812ho1289hg18hoif3h1o98g3hgq
NaN

Lisp info principalement de Practical Common Lisp .

Modifier, joué correctement jusqu'à 56 caractères

(format t "~:[NaN~;~:*~r~]"(ignore-errors(floor(read))))

Cette version fonctionne plutôt différemment. Au lieu de lire une ligne et de la convertir, il appelle le lecteur lisp pour interpréter l'entrée comme une expression s lisp, tente de l'utiliser comme un nombre, et si des erreurs sont produites les ignore produisant nil pour alimenter la chaîne de format conditionnelle. C'est peut-être la première fois que j'ai vu de lisp produire un programme vraiment laconique ... Fun!

  • (read) Appelle le lecteur / analyseur lisp pour lire une expression à partir de l'entrée standard et la convertir en un objet approprié
  • (floor) tente de convertir n'importe quel type numérique en entier inférieur le plus proche, les types non numériques provoquent une erreur
  • (ignore-errors ...) fait ce qu'il dit sur l'étain, il attrape et ignore toutes les erreurs dans l'expression incluse, renvoyant nil pour alimenter la branche NaN de la chaîne de formatage
Tom Scogland
la source
Ce n'est certainement pas un problème que la question ancienne :) J'ai modifié votre réponse pour inclure le nom de la langue et le nombre de caractères dans un en-tête.
ProgramFOX
Merci pour les modifications, je n'ai pas encore obtenu la syntaxe Stack * pour ces choses. Je suis rentré et j'ai corrigé une erreur que j'ai faite dans la description du conditionnel dans la chaîne de format.
Tom Scogland
3

PHP, 327 310 308 octets

<?$a=['',one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,0,fif,0,0,eigh];echo($n=$argv[1])>999?$a[$n/1000].' thousand ':'',$n%1000>99?$a[$n/100%10].' hundred ':'',$n?($k=$n%100)<20?($a[$k]?:$a[$k%10]).[teen][$k<13]:[2=>twen,thir,'for',fif,six,seven,eigh,nine][$k/10].'ty '.$a[$k%10]:zero;

prend le nombre comme paramètre, fonctionne pour 0 <= n <= 12999

panne

// define names
$a=['',one,two,three,four,five,six,seven,eight,nine,
    ten,eleven,twelve,thir,0,fif,0,0,eigh];
// print ...
echo
    ($n=$argv[1])>999?$a[$n/1000].' thousand ':'',                  // thousands
    $n%1000>99?$a[$n/100%10].' hundred ':'',                        // hundreds
    $n?
        // if remains <20:
        ($k=$n%100)<20?
            ($a[$k]?:$a[$k%10]) // no value at index (0,14,16,17,19)? value from index%10
            .[teen][$k<13]      // append "teen" for $k>12
        // else:
        :[2=>twen,thir,'for',fif,six,seven,eigh,nine][$k/10].'ty '  // tens
        .$a[$k%10]                                                  // ones
    // "zero" for $n==0
    :zero
;
Titus
la source
2

SAS, 70 caractères

data;window w n;display w;if n=. then put 'NaN';else put n words.;run;

Les instructions windowet displayouvrent l'invite de commande SAS. L'entrée pour nva sur la ligne 1. Cela profite du format SAS words.qui imprime le nombre sous la forme d'un mot ou d'une série de mots avec "et", "" et "-" selon le cas.

Alex A.
la source
2

PHP

777 caractères

C'est certainement une tentative terrible, mais vous ne pouvez pas m'accuser de tirer parti des lacunes, et c'est un chiffre très chanceux. Merci à ProgramFOX pour l'astuce.

<?php $i=9212;$b = array('zero','one','two','three','four','five','six','seven','eight','nine');$t='teen';$c = array('ten','eleven','tweleve','thir'.$t,$b[4].$t,'fif'.$t,$b[6].$t,$b[7].$t,$b[8].$t,$b[9].$t);$d = array('','','twenty','thirty','fourty','fifty','sixty','seventy','eighty','ninety');$e='hundred';$f='thousand';$j=str_split($i);if (strlen($i)===1){$a=$b[$i];}elseif (strlen($i)===3){$k=1;$a=$b[$j[0]].' '.$e.' '.x($j,$k);}elseif (strlen($i)===4){$k=2;$a=$b[$j[0]].' '.$f.' '.$b[$j[1]].' '.$e.' '.x($j,$k);}elseif (substr($i, -2, 1)==='1'){$a=$c[$j[1]];}else{$a=$d[$j[0]].' '.$b[$j[1]];}$a = str_replace('zero hundred','',$a);echo $a;function x($j,$k){global $i, $b, $c, $d;if (substr($i, -2, 1)==='1'){return $c[$j[$k+1]];}else{return $d[$j[$k]].' '.$b[$j[$k+1]];}}

Longue main

<?php
// Input
$i=9212;
// 0-9
$b = array('zero','one','two','three','four','five','six','seven','eight','nine');
// 10-19 (Very tricky)
$t='teen';
$c = array('ten','eleven','tweleve','thir'.$t,$b[4].$t,'fif'.$t,$b[6].$t,$b[7].$t,$b[8].$t,$b[9].$t); 
// Left digit of 20-99
$d = array('','','twenty','thirty','fourty','fifty','sixty','seventy','eighty','ninety');
// Hundreds
$e='hundred';
// Thousands
$f='thousand';
// Split input
$j=str_split($i);
// 1 digit inputs
if (strlen($i)===1){$a=$b[$i];}
// 3 digit input
elseif (strlen($i)===3){$k=1;$a=$b[$j[0]].' '.$e.' '.x($j,$k);}
// 4 digit input
elseif (strlen($i)===4){$k=2;$a=$b[$j[0]].' '.$f.' '.$b[$j[1]].' '.$e.' '.x($j,$k);}
// 10-19
elseif (substr($i, -2, 1)==='1'){$a=$c[$j[1]];}
// 20-99
else{$a=$d[$j[0]].' '.$b[$j[1]];}
// Fix for thousand numbers
$a = str_replace('zero hundred','',$a);
// Result
echo $a;
// Abstracted function last 2 digits for 3 and 4 digit numbers
function x($j,$k){
    global $i, $b, $c, $d;
    // 10-19
    if (substr($i, -2, 1)==='1'){return $c[$j[$k+1]];}
    // 20-99
    else{return $d[$j[$k]].' '.$b[$j[$k+1]];}
}
OIE
la source
1
Je pense que vous pouvez réduire votre code en créant des tableaux comme celui - ci: array('zero','one','two').
ProgramFOX
@ProgramFOX ou même ['zero','one','two'](php 5.4+). Et si cela ne vous dérange pas E_NOTICE, [zero,one,two]cela fonctionnerait aussi.
primo
Je devrais le mettre à jour, mais le 777 est un chiffre tellement chanceux.
Goose
+1 pour vos efforts. PHP est tragiquement sous-représenté dans le golf de code.
primo
1

Python 2.x - 378

Dérivée de la réponse de Fireflys, bien qu'en changeant Ppour inclure des millions ou des milliards de milliards, etc., elle pourrait être récursivement utilisée pour n'importe quelle gamme de nombres positifs. Cela prend également en charge des valeurs jusqu'à 999 999

O=",one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,,fif,,,eigh,,,,twen,thir,for,fif,,,eigh,".split(",")
P=",thousand".split(',')
def N(s,p=0):
 h,s=divmod(s,1000);x=N(h,p+1)if h>0 else" "
 if s<20:x+=O[s]or O[s-10]+["","teen"][s>12]
 elif s<100:x+=(O[s/10+20]or O[s/10])+"ty"+N(s%10)
 else:x+=N(s/100)+"hundred"+N(s%100)
 return x+" "+P[p]
print N(input())

Exemple de test (l'entrée est <<<, la sortie est >>>):

<<< 1234
>>> one thousand two hundred thirty four

<<< 999999
>>>  nine hundred ninety nine   thousand nine hundred ninety nine

Bien que, si quelqu'un peut expliquer cet étrange problème de "dépassement de mémoire tampon" que j'ai, ce serait exagéré ...

<<< -1
>>>  nine hundred ninety nine

<<< -2
>>>  nine hundred ninety eight

la source
print divmod(-2,1000) #-> (-1, 998)
primo
Oh bien sûr. Je pensais que cela pourrait prendre une valeur absolue ou quelque chose. Mais il y a -1*1000et un "reste" de 998.
1

SmileBASIC, 365 trois cent quarante-sept octets

DIM N$[22]D$="OneTwoThreeFourFiveSixSevenEightNineTenElevenTwelveThirFourFifSixSevenEighNineTwenFor
WHILE LEN(D$)INC I,D$[0]<"_
INC N$[I],SHIFT(D$)WEND
INPUT N
W=N MOD 100C%=N/100MOD 10M%=N/1E3T=W<20X=W/10>>0?(N$[M%]+" Thousand ")*!!M%+(N$[C%]+" Hundred ")*!!C%+(N$[X+10+(X==2)*8+(X==4)*7]+"ty "+N$[N MOD 10])*!T+N$[W*T]+"teen"*(T&&W>12)+"Zero"*!N

Il y a un espace de fin si les un ou deux derniers chiffres sont 0.

12Me21
la source
0

MOO - 55 caractères

player:tell($string_utils:english_number(read(player)))

Ou, si je n'ai pas besoin d'imprimer sur "stdout" - 42 caractères: $string_utils:english_number(read(player))

Remarque: ce code n'imprime aucune invite sur la sortie standard et s'imprime zeroau lieu de NaNlorsque l'entrée n'est pas un nombre.

En prime, ce code peut gérer n'importe quel nombre avec les limites de la langue moo ( 2147483647- -2147483648).

pppery
la source
0

Wolfram Language 27 40 octets

Faisant usage de la fonction native, IntegerName,

 Check[Input[]~IntegerName~"Words","NaN"]

Ce qui précède invite l'utilisateur à entrer ses informations. La présente implémentation renvoie "NaN" si l'utilisateur entre autre chose qu'un entier.


Quelques exemples (avec entrées prédéfinies) :

 Check[243~IntegerName~"Words","NaN"]

deux cent quarante-trois


 Check[1234567890~IntegerName~"Words","NaN"]   

un milliard, deux cent trente-quatre millions, cinq cent soixante-sept mille, huit cent quatre-vingt-dix


 Check["abc"~IntegerName~"Words","NaN"]  

NaN

DavidC
la source
0

Python 2 , 333 octets

def f(n):S=str.split;D=S('z one two three four five six seven eight nine');K=' fif six seven eigh nine';k=n/1000;n,m=n/100%10,n%100;e,d=m/10,m%10;return' '.join([k and f(k),'thousand']*(k>0)+[D[n],'hundred']*(n>0)+([S('ten eleven twelve thir four'+K)[d]+'teen'*(d>2)]if 9<m<20else[S('twen thir for'+K)[e-2]+'ty']*(e>0)+[D[d]]*(d>0)))

Essayez-le en ligne!

C'est bon pour 1 à 999 999 inclus.

Chas Brown
la source
0

Pyth, 239 242 octets

L:rjdb6"  +"dAm+cd;"nine"," one two three four five six seven eight""  twen thir for fif six seven eigh"|y_.ey+Wk.e?Y?thZjd,?hZ+@HhZ"ty"""@GeZ@+c"ten eleven twelve"d+R"teen"+c"thir four"d>H5eZ?hZ+@GhZ" hundred"""c.[03_b]1"thousand"c_jQT3"zero

L'entrée est un entier dans la plage [0-999,999]. Essayez-le en ligne ici . Explication en attente.

Version précédente, opération très similaire, mais ne prend pas en charge 0:

L:rjdb6"  +"dJc" one two three four five six seven eight nine"dKc"  twen thir for fif six seven eigh nine"dy_.ey+Wk.e?Y?thZjd,?hZ+@KhZ"ty"""@JeZ@+c"ten eleven twelve"d+R"teen"+c"thir four"d>K5eZ?hZ+@JhZ" hundred"""c.[03_b]1"thousand"c_jQT3

Explication de la version précédente:

Implicit: Q=eval(input()), d=" "

Step 1: output formatting helper function
L:rjdb6"  +"d   
L               Define a function, y(b):
   jdb          Join b on spaces
  r   6         Strip whitespace from beginning and end
 :              In the above, replace...
       "  +"    ... strings of more than one space...
            d   ... with a single space

Step 2: Define number lookup lists
Jc"..."dKc"..."d   
  "..."            Lookup string
 c     d           Split the above on spaces
J                  Store in J - this is list of unit names
        Kc"..."d   As above, but storing in K - this is list of tens names, without "ty"

Step 3: Bringing it all together
y_.ey+Wk.e?Y?thZjd,?hZ+@KhZ"ty"""@JeZ@+c"ten eleven twelve"d+R"teen"+c"thir four"d>K5eZ?hZ+@JhZ" hundred"""c.[03_b]1"thousand"c_jQT3   
                                                                                                                                jQT    Get digits of Q
                                                                                                                               _       Reverse
                                                                                                                              c    3   Split into groups of 3
  .e                                                                                                                                   Map the above, element as b, index as k, using:
                                                                                                                _b                       Reverse the digits in the group
                                                                                                            .[03                         Pad the above on the left with 0 to length 3
                                                                                                           c      ]1                     Chop at index 1 - [1,2,3] => [[1],[2,3]]
        .e                                                                                                                               Map the above, element as Z, index as Y, using:
          ?Y                                                                                                                               If second element in the group (i.e. tens and units):
            ?thZ                                                                                                                             If (tens - 1) is non-zero (i.e. 0 or >=2):
                   ?hZ                                                                                                                         If tens is non-zero:
                       @KhZ                                                                                                                      Lookup in tens names
                      +    "ty"                                                                                                                  Append "ty"
                                                                                                                                               Else:
                               ""                                                                                                                Empty string
                  ,                                                                                                                            Create two-element list of the above with...
                                 @JeZ                                                                                                          ... lookup units name
                jd                                                                                                                             Join the above on a space - this covers [0-9] and [20-99]
                                                                                                                                             Else:
                                                                     c"thir four"d                                                             ["thir", "four"]
                                                                    +             >K5                                                          Append last 5 element of tens names ("fif" onwards)
                                                            +R"teen"                                                                           Append "teen" to each string in the above
                                      +c"ten eleven twelve"d                                                                                   Prepend ["ten", "eleven", "twelve"]
                                     @                                               eZ                                                        Take string at index of units column - this covers [10-19]
                                                                                                                                           Else: (i.e. hundreds column)
                                                                                       ?hZ                                                   If hundreds column is non-zero:
                                                                                           @JhZ                                                Lookup units name
                                                                                          +    " hundred"                                      Append " hundred"
                                                                                                         ""                                  Else: empty string
                                                                                                                                         Result of map is two element list of [hundreds name, tens and units name]
      Wk                                                                                                                                 If k is nonzero (i.e. dealing with thousands group)...
     +                                                                                                              "thousand"           ... Append "thousand"
    y                                                                                                                                    Apply output formatting (join on spaces, strip, deduplicate spaces)
                                                                                                                                       Result of map is [units group string, thousands group string]
 _                                                                                                                                     Reverse group ordering to put thousands back in front
y                                                                                                                                      Apply output formatting again, implicit print
Sok
la source