Converter inglês em um número sem built-ins ou bibliotecas

14

Esse desafio é semelhante a esse outro , no entanto, fiz uma restrição (veja o texto em negrito abaixo) que acho que tornaria muito diferente e (espero) divertido também.

O desafio

Escreva um programa ou uma função em qualquer linguagem de programação que tome como entrada o nome em inglês de um número inteiro positivo que nnão exceda 100e retorne ncomo um número inteiro.

As brechas padrão são proibidas e você não pode usar nenhuma função interna, ferramenta externa ou biblioteca que já faça esse trabalho .

O código-fonte mais curto em bytes vence.

Teste

Aqui estão todos os input->outputcasos:

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
twenty-one       -> 21
twenty-two       -> 22
twenty-three     -> 23
twenty-four      -> 24
twenty-five      -> 25
twenty-six       -> 26
twenty-seven     -> 27
twenty-eight     -> 28
twenty-nine      -> 29
thirty           -> 30
thirty-one       -> 31
thirty-two       -> 32
thirty-three     -> 33
thirty-four      -> 34
thirty-five      -> 35
thirty-six       -> 36
thirty-seven     -> 37
thirty-eight     -> 38
thirty-nine      -> 39
forty            -> 40
forty-one        -> 41
forty-two        -> 42
forty-three      -> 43
forty-four       -> 44
forty-five       -> 45
forty-six        -> 46
forty-seven      -> 47
forty-eight      -> 48
forty-nine       -> 49
fifty            -> 50
fifty-one        -> 51
fifty-two        -> 52
fifty-three      -> 53
fifty-four       -> 54
fifty-five       -> 55
fifty-six        -> 56
fifty-seven      -> 57
fifty-eight      -> 58
fifty-nine       -> 59
sixty            -> 60
sixty-one        -> 61
sixty-two        -> 62
sixty-three      -> 63
sixty-four       -> 64
sixty-five       -> 65
sixty-six        -> 66
sixty-seven      -> 67
sixty-eight      -> 68
sixty-nine       -> 69
seventy          -> 70
seventy-one      -> 71
seventy-two      -> 72
seventy-three    -> 73
seventy-four     -> 74
seventy-five     -> 75
seventy-six      -> 76
seventy-seven    -> 77
seventy-eight    -> 78
seventy-nine     -> 79
eighty           -> 80
eighty-one       -> 81
eighty-two       -> 82
eighty-three     -> 83
eighty-four      -> 84
eighty-five      -> 85
eighty-six       -> 86
eighty-seven     -> 87
eighty-eight     -> 88
eighty-nine      -> 89
ninety           -> 90
ninety-one       -> 91
ninety-two       -> 92
ninety-three     -> 93
ninety-four      -> 94
ninety-five      -> 95
ninety-six       -> 96
ninety-seven     -> 97
ninety-eight     -> 98
ninety-nine      -> 99
one hundred      -> 100
Prumo
fonte
1
Que tal um built-in que faz metade do trabalho, por exemplo, encontrar o nome unicode de um ponto de código.
Brad Gilbert b2gills
@ BradGilbertb2gills Não, não está bem.
Bob

Respostas:

22

C, 160 bytes

g(char*s){char i=1,r=0,*p="k^[#>Pcx.yI<7CZpVgmH:o]sYK$2";for(;*s^'-'&&*s;r+=*s++|9);r=r%45+77;for(;*p!=r;p++,i++);return((*s^'-')?0:g(s+1))+(i<21?i:10*(i-18));}

Teste-o

int main ()
{
    char* w[] = {"", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "twenty-one", "twenty-two", "twenty-three", "twenty-four", "twenty-five", "twenty-six", "twenty-seven", "twenty-eight", "twenty-nine", "thirty", "thirty-one", "thirty-two", "thirty-three", "thirty-four", "thirty-five", "thirty-six", "thirty-seven", "thirty-eight", "thirty-nine", "forty", "forty-one", "forty-two", "forty-three", "forty-four", "forty-five", "forty-six", "forty-seven", "forty-eight", "forty-nine", "fifty", "fifty-one", "fifty-two", "fifty-three", "fifty-four", "fifty-five", "fifty-six", "fifty-seven", "fifty-eight", "fifty-nine", "sixty", "sixty-one", "sixty-two", "sixty-three", "sixty-four", "sixty-five", "sixty-six", "sixty-seven", "sixty-eight", "sixty-nine", "seventy", "seventy-one", "seventy-two", "seventy-three", "seventy-four", "seventy-five", "seventy-six", "seventy-seven", "seventy-eight", "seventy-nine", "eighty", "eighty-one", "eighty-two", "eighty-three", "eighty-four", "eighty-five", "eighty-six", "eighty-seven", "eighty-eight", "eighty-nine", "ninety", "ninety-one", "ninety-two", "ninety-three", "ninety-four", "ninety-five", "ninety-six", "ninety-seven", "ninety-eight", "ninety-nine", "one hundred"};

    int n;
    for (n = 1; n <= 100; n++)
    {
        printf ("%s -> %d\n", w[n], g(w[n]));
        if (n != g(w[n]))
        {
            printf ("Error at n = %d", n);
            return 1;
        }
    }
    return 0;
}

Como funciona

Depois de algumas tentativas, eu encontrei uma função que mapeia os números "excepcionais" one, two, three, four, five, six, seven, eight, nine,ten , eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, thirty, forty, fifty, sixty, seventy, eighty, ninety, one hundred, para os caracteres ASCII imprimíveis k, ., [, <, *, , c, K, w, y, e, (, S, _, -, C, ), 7, =, 4, &,o, ], s, Y, g, m, N, Respectivamente.

Esta função é:

char hash (char* s)
{
    char r = 0;

    while (*s)
    {
        r += *s|9;
        s++;
    }

    return r%45+77;
}

O programa golfed calcula a hashfunção da entrada até atingir o final da string ou do caractere -. Em seguida, ele pesquisa o hash na string k.[<* cKwye(S_-C)7=4&o]sYgmNe determina o número correspondente. Se o final da sequência de entrada for atingido, o número será retornado; se, em vez disso, for -atingido, será retornado o número mais o resultado do programa de golfe aplicado ao restante da sequência de entrada.

Prumo
fonte
Estou pensando, se houvesse uma versão de golfe de C, pode realmente bater linguagens como CJam Pyth Japt etc ...
busukxuan
11

JavaScript (ES6), 175 166 163 156 156 153 147 bytes

Guardado 7 bytes graças a @Neil

a=>+a.replace(/.+te|.*el|y$/,x=>x[1]?'on-'+x:'-d').split(/ |-|dr/).map(x=>"un|d,on|le,w,th,fo,f,x,s,h,i,".split`,`.findIndex(y=>x.match(y))).join``

Verifique aqui:

Como funciona

A idéia básica é dividir cada número em suas palavras-dígito e depois mapear cada palavra para o dígito correspondente. Quase todas as palavras são configuradas para serem correspondidas corretamente com uma regex simples, mas existem algumas anomalias:

  • eleventhrough nineteen: se a palavra contiver um el, ou a teno meio (para evitar ten), adicionamos on-a ao início, alterando-os para on-eleventhrough on-nineteen.
  • twenty, thirty, Etc .: substituindo um arrasto ycom -dmudanças para estes twent-d, thirt-detc.

Agora nos dividimos em hífens, espaços dres. Isso divide tudo de 11 a 99 em suas palavras-dígito correspondentes e "one hundred"em [one,hun,ed]. Em seguida, mapeamos cada uma dessas palavras por meio de uma matriz de expressões regulares e mantemos o índice daquele que corresponde primeiro.

0: /un|d/ - This matches the "hun" and "ed" in 100, as well as the "d" we placed on the end of 20, 30, etc.
1: /on|le/ - Matches "one" and the "on" we placed on the beginning of 11 through 19, along with "eleven".
2: /w/ - Matches "two", "twelve", and "twenty".
3: /th/ - Matches "three" and "thirty".
4: /fo/ - Matches "four" and "forty".
5: /f/ - "five" and "fifty" are the only words by now that contain an "f".
6: /x/ - "six" and "sixty" are the only words that contain an "x".
7: /s/ - "seven" and "seventy" are the only words by now that contain an "s".
8: /h/ - "eight" and "eighty" are the only words by now that contain an "h".
9: /i/ - "nine" and "ninety" are the only words by now that contain an "i".
10: /<empty>/ - "ten" is the only word left, but it still has to be matched.

Até agora, cada entrada será a matriz dos dígitos adequados. Tudo o que precisamos fazer é juntá-los join``, converter para um número com unário +e pronto.

ETHproductions
fonte
Por favor explique.
10242 Bob
@ Bob Claro, explicação adicionada.
ETHproductions
Não .findIndex(y=>x.match(y))funciona?
Neil
@ Neil eu não sabia que sim, mas sim, obrigado!
ETHproductions
Tenho certeza que você pode usar o pseudônimo replace.
Mama Fun Roll
6

sh + coreutils, 112 bytes

Pode ser executado em todos os casos de teste de uma só vez, um por linha.

sed -r "`awk '$0="s/"$0"/+"NR"/g"'<<<"on
tw
th
fo
fi
si
se
ei
ni
te|lv
el"`
s/ /y0/
s/y/*10/
s/^\+|[a-z-]//g"|bc

Explicação

O backticked é awkavaliado para o sedscript

s/on/+1/g       # one, one hundred
s/tw/+2/g       # two, twelve, twenty
s/th/+3/g       # three, thirteen, thirty
s/fo/+4/g       # ...
s/fi/+5/g
s/si/+6/g
s/se/+7/g
s/ei/+8/g
s/ni/+9/g
s/te|lv/+10/g   # ten, -teen, twelve
s/el/+11/g      # eleven

que transforma partes de números em sua representação numérica.

fife            ->    +5ve
ten             ->    +10n
eleven          ->    +11even
twelve          ->    +2e+10e
sixteen         ->    +6x+10en
thirty-seven    ->    +3irty-+7ven
forty-four      ->    +4rty-+4ur
eighty          ->    +8ghty
one hundred     ->    +1e hundred

As linhas adicionais do script sed

s/ /y0/
s/y/*10/

cuidar de -tys e one hundred.

+3irty-+7ven    ->    +3irt*10-+7ven
+4rty-+4ur      ->    +4rt*10-+4ur
+8ghty          ->    +8ght*10
+1e hundred     ->    +1ey0hundred      ->    +1e*100hundred

Por fim, remova os iniciais +e tudo o que não é +, *ou um dígito.

s/^\+|[a-z-]//g"

Apenas expressões matemáticas permanecem

fife            ->    5
sixteen         ->    6+10
forty-four      ->    4*10+4
eighty          ->    8*10
one hundred     ->    1*100

e pode ser canalizado bc.

Rainer P.
fonte
4

Pitão, 79 76 75 68 bytes

Obrigado @ETHproductions por 7 bytes.

?}"hu"z100sm*+hxc."ewEСBu­["2<d2?|}"een"d}"lv"dTZ?}"ty"dT1cz\-

Basicamente, primeiro verifique a caixa do canto 100 e, em seguida, use uma matriz das duas primeiras letras dos números de 0 a 11 para determinar a semântica da entrada e modifique o valor de acordo com o sufixo ("-ty" e "-teen"; " lv "em 12 é outro caso de canto). Primeiro, divida a entrada em uma lista de palavras, depois mapeie cada uma delas com um valor e as resuma.

No pseudocódigo pitônico:

                           z = input()    # raw, unevaluated
                           Z = 0
                           T = 10
?}"hu"z                    if "hu" in z:  # checks if input is 100
  100                        print(100)
                           else:
sm                           sum(map( lambda d: # evaluates each word, then sum
  *                            multiply(
   +hxc."ewEСBu­["2<d2           plusOne(chop("ontwth...niteel",2).index(d[:2])) + \
                                 # chops string into ["on","tw",..."el"]
                                 # ."ewEСBu­[" is a packed string
     ?|}"een"d}"lv"dTZ               (T if "een" in d or "lv" in d else Z),
                                     # add 10 for numbers from 12 to 19
   ?}"ty"dT1                     T if "ty" in d else 1),  # times 10 if "-ty"
  cz\-                         z.split("-"))  # splits input into words

Suíte de teste


Python 3, 218 bytes

z=input()
if "hu" in z:print(100);exit()
print(sum(map(lambda d:([0,"on","tw","th","fo","fi","si","se","ei","ni","te","el"].index(d[:2])+(10 if "een" in d or "lv" in d else 0))*(10 if "ty" in d else 1),z.split("-"))))

Basicamente idêntico à resposta Pyth.


Fora do assunto:

Acabei de descobrir uma versão significativa da resposta à vida, ao universo e tudo mais: são galhos sedentos de chá. Uau, galhos que anseiam por chá! Não tenho certeza de quantas outras respostas fazem isso, mas para minha resposta, se a entrada for "chá com sede", a saída é 42.

busukxuan
fonte
Eu acredito que você pode salvar sete bytes usando uma string compactada . Copie a saída e coloque-a no lugar "ontwthfofisiseeiniteel"deste programa.
ETHproductions
@ETHproductions Uau, obrigado! A última vez que verifiquei, ainda havia "ze" na cabeça da corda e a embalagem não funcionava. Não chequei mais uma vez depois de jogar golfe. Mais uma vez, obrigado xD
busukxuan
@ETHproductions sim, eu realmente fiz, está sob o pseudocódigo.
11786 Buschxuan
2

Python 3, 365 361 310 303 caracteres

Golfe

def f(a):
 y=0
 for i in a.split("-"):
  x="one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir;four;fif;six;seven;eigh;nine;twenty,thirty,forty,fifty,sixty,seventy,eighty,ninety,one hundred".replace(";","teen,").split(",").index(i)
  y+=x+1 if x<20 else range(30,110,10)[x-20]
 return y

Ungolfed

 def nameToNumber (numberName):
    names = ["one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen",
             "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","thirty","forty","fifty",
             "sixty","seventy","eighty","ninety","one hundred"]
    numbers = range(30, 110, 10)
    number = 0
    for n in numberName.split("-"):
        x = names.index(n)
        number += x + 1 if x < 20 else numbers[x - 20]
    return number
Argenis García
fonte
45 caracteres mais curtos: n="one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen,twenty,thirty,forty,fifty,sixty,seventy,eighty,ninety,one hundred".split(",")Mas, como eu vejo, deve funcionar sem atribuí-lo à variável n, basta chamá .index()-lo diretamente.
manatwork
7 caracteres mais curtos: "one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir;four;fif;six;seven;eigh;nine;twenty,thirty,forty,fifty,sixty,seventy,eighty,ninety,one hundred".replace(";","teen,").split(",").
Manatwork
O mecanismo do site StackExchange tem um hábito irritante: ele insere caracteres invisíveis (não-marceneiro de largura zero do U200C e espaço de largura zero do U200B) no código postado nos comentários. Você os copiou também. Editei sua postagem para removê-los.
manatwork
2

Haskell, 252 231 bytes

let l=words;k=l"six seven eight nine";w=l"one two three four five"++k++l"ten eleven twelve"++((++"teen")<$>l"thir four fif"++k)++[n++"ty"++s|n<-l"twen thir for fif"++k,s<-"":['-':x|x<-take 9w]]in maybe 100id.flip lookup(zip w[1..])

Isso cria uma lista de todos os nomes de números em inglês de "um" a "noventa e nove" e, em seguida, consulta o índice da entrada. Se não existir, estamos no caso da borda "cem", então ele retorna 100, caso contrário, ele retornará o índice.

Ungolfed

-- k in the golfed variant
common = words "six seven eight nine" 

-- w in the golfed variant
numbers = words "one two three four five" ++ common
       ++ words "ten eleven twelve" ++ [p ++ "teen" | p <- words "thir four fif" ++ common]
       ++ [p ++ "ty" ++ s| p <- words "twen thir for fif" ++ common
                         , s <- "" : map ('-':) (take 9 numbers)]

-- part of the expression in the golfed variant
convert :: String -> Int
convert s = maybe 100 id $ lookup s $ zip numbers [1..]
Zeta
fonte
2

Python 2, 275 caracteres

def x(n):a='one two three four five six seven eight nine ten eleven twelve'.split();t='twen thir four fif six seven eigh nine'.split();b=[i+'teen'for i in t[1:]];c=[i+'ty'for i in t];return(a+b+[i+j for i in c for j in ['']+['-'+k for k in a[:9]]]+['one hundred']).index(n)+1

Simples cria uma lista de todos os números e encontra o índice.

Pedro
fonte
1

Japt, 82 bytes

+Ur`(.+)¿``¿-$1` r"y$""-d" q$/ |-|dr/$ £`un|Üaiwo|ØÏ¿ifoifix¿iÊ¿¿e¿iv`qi b_XfZ}Ãq

Cada ¿um representa um caractere não imprimível. Teste online!

Com base na minha resposta JS. Subtraia um byte se a saída não precisar ser um número inteiro, pois pareceria exatamente o mesmo que uma string.

Como funciona

+Ur`(.+)¿` `¿-$1`  r"y$""-d" q/ |-|dr/ £  `un|Üaiwo|ØÏ¿ifoifix¿iÊ¿¿e¿iv`          qi b_ XfZ}à q
+Ur"(.+)te""on-$1" r"y$""-d" q/ |-|dr/ mX{"un|dioniwo|wenithifoifixisihineiteiniv"qi bZ{XfZ}} q

Ur"(.+)te""on-$1" // Replace "thirteen", "fourteen", etc. with "on-thiren", "on-fouren", etc.
r"y$""-d"         // Replace "twenty", "thirty", etc. with "twent-d", "thirt-d", etc.
q/ |-|dr/         // Split at occurances of a space, hyphen, or "dr". By now,
                  // "one", "thirteen", "twenty", "sixty-six", "one hundred" will have become:
                  // "one", "on" "thiren", "twent" "d", "sixty" "six", "one" "hun" "ed"
mX         }      // Map each item X in the resulting array to:
"..."qi           //  Take this string, split at "i"s,
b_XfZ}            //  and find the first item Z where X.match(RegExp(Z)) is not null.
                  //  See my JS answer to learn exactly how this works.
                  // Our previous example is now
                  // "1", "1" "3", "2" "0", "6" "6", "1" "0" "0"
+              q  // Join and convert to integer.
                  // 1, 13, 20, 66, 100
ETHproductions
fonte
1

JavaScript, 214 199 bytes

Como sempre: acontece que isso é muito longo para competir, mas agora que eu terminei, seria um desperdício não publicar isso.

Talvez exista uma maneira óbvia de jogar golfe mais que eu tenha esquecido?

e=s=>s.slice(-1)=='d'?100:'  ontwthfofisiseeinite'.indexOf(s.slice(0,2))/2;f=s=>([t,u]=s.split('-'),~s.indexOf`le`?11:~s.indexOf`lv`?12:e(t)+(t.slice(-3)=='een')*10+''+(u?e(u):t.slice(-1)=='y'?0:''))

JSFiddle para casos de teste

vvye
fonte
1
Que tal mudar fpara f=s=>([t,u]=s.split('-'),~s.indexOf('le')?11:~s.indexOf('lv')?12:e(t)+(t.slice(-3)=='een')*10+''+(u?e(u):t.slice(-1)=='y'?0:''))? Além disso, um argumento de cadeia única pode ser passado para uma função da seguinte maneira:s.indexOf`lv`
ETHproductions
@ETHproductions Isso é ótimo, obrigado! Eu não sabia que JS tinha um operador de vírgula, e a abreviação para a passagem de strings também é realmente útil.
vvye
1

Perl, 158 bytes

@s=split/(\d+)/,'te1ten0l1le1on1tw2th3fo4fi5si6se7ei8ni9d00';foreach(split'-',$n=$ARGV[0]){for($i=0;$i<$#s;$i+=2){m/$s[$i]/&&print$s[$i+1]}}$n=~/ty$/&&print 0

É executado a partir da linha de comando. one hundreddeve ser inserido "one hundred"para impedir que seja interpretado como duas entradas.

CJ Dennis
fonte