Convertendo números inteiros para palavras em inglês


21

O objetivo deste código golf é converter números inteiros em palavras em inglês.

O programa solicita entrada. Se essa entrada não for um número inteiro, imprima NaN. Se for um número inteiro, converta-o para palavras em inglês e imprima-as. Entrada mínima: 0 (zero). Entrada máxima: 9000 (nove mil).
Portanto, 5retornos five(maiúsculas e minúsculas não importam) e 500retornos five hundredou five-hundred(traços não importam).

Algumas outras regras:

Um oneantes hundredou thousandé opcional: one hundredestá correto, mas hundredtambém (se a entrada for, é 100claro).

A palavra andpor exemplo também one hundred and forty fiveé opcional.

O espaço em branco é importante. Então, para 500, five-hundredou five hundredestá correto, mas fivehundrednão está.

Boa sorte!



Essa resposta no SO faz coisas semelhantes, mas não é código-golfe.
ST3

Respostas:


7

Perl 281 bytes

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

Novas linhas adicionadas para sanidade horizontal. O acima pode ser usado interativamente ou canalizando um valor via stdin.

Funciona corretamente para todos os valores inteiros no intervalo [0, 19999] , valores fora desse intervalo exibem comportamento indefinido. Valores não inteiros serão truncados em direção a zero e, como tal, somente os valores verdadeiramente não numéricos serão relatados NaN.

Uso da amostra:

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

Saída de amostra:

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

"1000000000: Mil"? 17.2 não deveria imprimir "NaN"?
DavidC

5
@DavidCarraher "... valores fora desse intervalo exibem comportamento indefinido . Valores não inteiros serão truncados em direção a zero e, como tal, somente valores verdadeiramente não numéricos serão reportados NaN."
Primo12

Como não sou especialista em Perl, faço a seguinte pergunta: este programa solicita entrada?
ProgramFOX

@ProgramFOX Atualizei-o para ler um valor de stdin (se executado de forma interativa, solicitará ao usuário um valor), em vez de ser uma função.
Primo15

13

JavaScript (375)

Provavelmente uma tentativa terrível, mas enfim, aqui vai ...

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()))

Bonito-impresso (como uma função):

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
}

Conversão de amostra (observe que ela sai mesmo NaNfora dos limites, ou seja, entrada inválida):

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

+1é muito difícil fazer melhor em uma linguagem como javascript. (você pode remover o espaço em N(s,z) {returnpara salvar 1 caractere)
Math chiller

Ah, haha, deve ter sentido falta dessa. Também pareço ter perdido um monte de caracteres na Ostring. Eu vou consertar isso ..
FireFly 13/13

11

Mathematica 60 57

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

Uso:

f[500]

quinhentos

Editar:

InputString[]~WolframAlpha~{{"NumberName", 1}, "Plaintext"}

3
Isso realmente não responde à pergunta. Eu disse que o usuário precisa inserir um número (usando a linha de comando ou uma caixa de prompt, por exemplo) e, em seguida, seu programa deve exibir as palavras (na linha de comando ou em uma caixa de mensagem, por exemplo). Seu código é apenas uma função para convertê-lo e seu programa não solicita entrada.
ProgramFOX

@ProgramFOX diz 'O usuário insere algo'. Isso não significa 'O programa solicita entrada'.
MrZander

@ MrZander: Bem, 'o programa solicita entrada' foi realmente o que eu quis dizer. Eu atualizar a minha pergunta, mas é claro, seria injusto se eu não seria a resposta de alephalpha upvote, então ele tem o meu +1
ProgramFOX

8

Lisp, 72 56 caracteres

Percebo 1) que isso é antigo e 2) que ele depende inteiramente da biblioteca padrão para funcionar, mas o fato de você poder fazer com que o sistema de impressão c-lisp faça esse tipo de coisa sempre me impressionou. Além disso, isso de fato recebe a entrada de um usuário, converte e imprime.

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

Totaliza 72 caracteres.

  • :junk-allowed faz com que parse-number inteiro retorne zero na falha, em vez de gerar um erro.
  • ~:[if-nil~;if-non-nill] condicional baseado em zero, manipula NaN onde necessário
  • ~:* faz backup da interpretação do argumento para consumir novamente a entrada
  • ~r imprime o número como uma sequência de palavras em inglês, conforme solicitado, exceto com pontuação totalmente corrigida

Amostra:

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

192hqfwoelkqhwef9812ho1289hg18hoif3h1o98g3hgq
NaN

Lisp informação principalmente de Practical Common Lisp .

Editar, jogado corretamente com até 56 caracteres

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

Esta versão funciona de maneira bastante diferente. Em vez de ler uma linha e convertê-la, ele invoca o leitor lisp para interpretar a entrada como uma expressão lisp s, tenta usá-la como um número e, se algum erro for produzido, os ignora, produzindo nada para alimentar a sequência de formatação condicional. Esta pode ser a primeira instância que eu vi do lisp produzindo um programa verdadeiramente conciso ... Divertido!

  • (read) Invoca o leitor / analisador lisp para ler uma expressão da entrada padrão e convertê-la em um objeto apropriado
  • (floor) tentativas de converter qualquer tipo numérico para o número inteiro inferior mais próximo, os tipos não numéricos causam um erro
  • (ignore-errors ...) faz o que diz na lata, captura e ignora quaisquer erros na expressão incluída, retornando nulo para alimentar o ramo NaN da sequência de formatação

Certamente não é problema que a pergunta antiga :) Editei sua resposta para incluir o nome do idioma e a contagem de caracteres em um cabeçalho.
precisa

Obrigado pelas edições, ainda não obtive a sintaxe Stack * para essas coisas. Voltamos e corrigimos um erro que cometi na descrição do condicional na string de formato também.
Tom Scogland

3

PHP, 327 310 308 bytes

<?$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;

toma o número como parâmetro, trabalha para 0 <= n <= 12999

demolir

// 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
;

2

SAS, 70 caracteres

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

As instruções windowe displayabrem o prompt de comandos do SAS. A entrada para ncontinua na linha 1. Isso tira proveito do formato SAS, words.que imprimirá o número como uma palavra ou série de palavras com "e", "" e "-" conforme apropriado.


2

PHP

777 caracteres

Esta é definitivamente uma tentativa terrível, mas você não pode me acusar de tirar proveito de quaisquer brechas, além de ser um número muito sortudo. Obrigado ao ProgramFOX pela dica.

<?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]];}}

Mão longa

<?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]];}
}

11
Eu acho que você pode encurtar o seu código através da criação de matrizes como este: array('zero','one','two').
precisa

@ProgramFOX ou mesmo ['zero','one','two'](php 5.4+). E se você não se importa E_NOTICE, [zero,one,two]também funcionaria.
primo

Eu deveria atualizá-lo, mas o 777 é um número de sorte.
Goose

+1 pelos seus esforços. O PHP é tragicamente sub-representado no código golf.
primo

1

Python 2.x - 378

A derivada da resposta de Fireflys, embora mudando Ppara incluir milhões ou trilhões, etc., poderia recursivamente ser usada para qualquer faixa de números positivos. Isso também suporta valores de até 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())

Teste de amostra (entrada é <<<, saída é >>>):

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

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

Embora, se alguém puder explicar esse problema estranho de "buffer underflow" que eu tenho, isso seria ótimo ...

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

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

print divmod(-2,1000) #-> (-1, 998)
Primo10

Ah, claro. Eu estava pensando que poderia levar um valor absoluto ou algo assim. Mas existe -1*1000e um "restante" de 998.

1

SmileBASIC, 365 Trezentos e Quarenta e Sete bytes

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

Há um espaço à direita se os últimos um ou dois dígitos forem 0.


0

MOO - 55 caracteres

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

Ou, se eu não precisar imprimir em "stdout" - 42 caracteres: $string_utils:english_number(read(player))

Nota: este código não imprime nenhum prompt na saída padrão e é impresso em zerovez de NaNquando a entrada não é um número.

Como um bônus, esse código pode lidar com qualquer número dentro dos limites do idioma moo ( 2147483647- -2147483648).


0

Wolfram Language 27 40 bytes

Fazendo uso da função nativa, IntegerName,

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

O acima solicita a entrada do usuário. A implementação atual retorna "NaN" se o usuário digitar algo diferente de um número inteiro.


Alguns exemplos (com entradas predefinidas) :

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

duzentos e quarenta e três


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

um bilhão, duzentos e trinta e quatro milhões, quinhentos e sessenta e sete mil, oitocentos e noventa


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

NaN


0

Python 2 , 333 bytes

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)))

Experimente online!

Isso é bom para 1 a 999.999, inclusive.


0

Pitão, 239 242 bytes

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

A entrada é um número inteiro no intervalo [0-999.999]. Experimente online aqui . Explicação pendente.

Versão anterior, operação muito semelhante, mas não suporta 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

Explicação da versão anterior:

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.