Converti l'inglese in un numero senza built-in o librerie


14

Questa sfida è simile a questa , tuttavia ho fatto una restrizione (vedi il testo in grassetto di seguito) che penso l'avrebbe resa molto diversa e (spero) divertente.

La sfida

Scrivi un programma o una funzione in qualsiasi linguaggio di programmazione che assume come input il nome inglese di un numero intero positivo nnon superiore 100e restituisce nun numero intero.

Sono vietate le scappatoie standard e non è possibile utilizzare alcuna funzione integrata, strumento esterno o libreria che già svolge questo lavoro .

Vince il codice sorgente più breve in byte.

Test

Ecco tutti i input->outputcasi:

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

1
Che dire di un built-in che fa metà del lavoro, ad esempio trovare il nome unicode di un punto di codice.
Brad Gilbert b2gills il

@ BradGilbertb2gills No, non va bene.
Bob

Risposte:


22

C, 160 byte

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

Provalo

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

Come funziona

Dopo alcuni tentativi, ho trovato una funzione che mappa i numeri "eccezionali" 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, per i caratteri ASCII stampabili k, ., [, <, *, , c, K, w, y, e, (, S, _, -, C, ), 7, =, 4, &,o,], s, Y, g, m, N, Rispettivamente.

Questa funzione è:

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

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

    return r%45+77;
}

Il programma golf calcola la hashfunzione dell'input fino a quando non raggiunge la fine della stringa o del carattere -. Quindi cerca l'hash nella stringa k.[<* cKwye(S_-C)7=4&o]sYgmNe determina il numero corrispondente. Se è stata raggiunta la fine della stringa di input, viene restituito il numero, se invece -viene raggiunto un numero, viene restituito il numero più il risultato del programma golf applicato al resto della stringa di input.


Sto pensando, se ci fosse una versione golfistica di C, potrebbe effettivamente battere lingue come CJam Pyth Japt ecc ...
busukxuan,

11

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

Salvato 7 byte grazie 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``

Verifica qui:

Come funziona

L'idea di base è quella di dividere ogni numero nelle sue parole-cifra, quindi mappare ogni parola alla cifra corrispondente. Quasi tutte le parole sono impostate per essere abbinate correttamente con una semplice regex, ma ci sono alcune anomalie:

  • elevenattraverso nineteen: se la parola contiene un el, o unte nel mezzo (per evitare ten), aggiungiamo on-a all'inizio, cambiandoli in on-eleventhrough on-nineteen.
  • twenty, thirtyecc.: sostituzione di un finaley con -dmodifiche a questi twent-d, thirt-decc

Ora ci dividiamo in trattini, spazi e dr s. Questo divide tutto da 11 a 99 nelle sue corrispondenti parole-cifre e "one hundred"in [one,hun,ed]. Quindi mappiamo ciascuna di queste parole attraverso una serie di regex e manteniamo l'indice di quella che corrisponde per prima.

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.

Ormai, ogni input sarà l'array delle cifre appropriate. Tutto quello che dobbiamo fare è unirli a loro join``, convertirli in un numero con unario +e il gioco è fatto.


Spiega per favore.
Bob

@Bob Sicuro, spiegazione aggiunta.
ETHproductions

Non .findIndex(y=>x.match(y))funziona?
Neil,

@Neil Non me ne ero reso conto, ma lo fa, grazie!
ETHproductions

Sono abbastanza sicuro che puoi alias replace.
Mama Fun Roll,

6

sh + coreutils, 112 byte

Può essere eseguito su tutti i test in una sola volta, uno per riga.

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

Spiegazione

Il backticked restituisce awklo 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

che trasforma parti di numeri nella loro rappresentazione numerica.

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

Le righe aggiuntive dello script sed

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

prendersi cura di -tys ed one hundred.

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

Infine, rimuovere leader +s e tutto ciò che non è +, *o una cifra.

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

Rimangono solo le espressioni matematiche

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

e può essere convogliato bc.


4

Pyth, 79 76 75 68 byte

Grazie a @ETHproductions per 7 byte.

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

Fondamentalmente controlla prima il caso d'angolo di 100, quindi utilizza una matrice delle prime due lettere dei numeri da 0 a 11 per determinare la semantica dell'input e modificare il valore in base al suffisso ("-ty" e "-teen"; " lv "in 12 è un altro caso d'angolo). Dividi innanzitutto l'input in un elenco di parole, quindi associa ognuna a un valore e riassumile.

In pseudocodice pythonic:

                           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

Suite di test


Python 3, 218 byte

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

Sostanzialmente identico alla risposta di Pyth.


Fuori tema:

Ho appena scoperto una versione significativa della risposta alla vita, all'universo e a tutto: sono rametti assetati di tè. Wow, ramoscelli che bramano il tè! Non sono sicuro di quante altre risposte lo facciano, ma per la mia risposta se l'input è "ramoscelli assetati di tè" l'output è 42.


Credo che puoi salvare sette byte usando una stringa compressa . Copia l'output e mettilo al posto di "ontwthfofisiseeiniteel"in questo programma.
ETHproductions

@ETHproductions Wow, grazie! L'ultima volta che ho controllato, c'era ancora "ze" all'inizio della corda e l'imballaggio non poteva funzionare. Non ho controllato ancora una volta dopo averlo giocato a golf. Ancora una volta, grazie xD
busukxuan,

@ETHproductions sì, in realtà l'ho fatto, è sotto lo pseudocodice.
busukxuan,

2

Python 3, 365 361 310 303 caratteri

golfed

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

45 caratteri più corti: 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(",")Ma come vedo, dovrebbe funzionare senza assegnarlo alla variabile n, basta chiamarlo .index()direttamente su di esso.
arte

7 caratteri più brevi: "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(",").
arte

Il motore del sito StackExchange ha un'abitudine irritante: inserisce caratteri invisibili (U200C Zero Width Non-Joiner e U200B Zero Width Space) nel codice pubblicato nei commenti. Li hai incollati anche tu. Ho modificato il tuo post per rimuoverli.
arte

2

Haskell, 252 231 byte

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

Questo crea un elenco di tutti i nomi di numeri inglesi da "uno" a "novantanove" e quindi cerca l'indice dell'input in alto. Se non esiste, siamo nel caso limite "cento", quindi ritorna 100, altrimenti restituirà l'indice.

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..]

2

Python 2, 275 caratteri

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

Crea semplicemente un elenco di ogni numero e trova l'indice.


1

Japt, 82 byte

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

Ciascuno ¿rappresenta un carattere non stampabile. Provalo online!

Basato sulla mia risposta JS. Sottrai un byte se l'output non deve essere un numero intero, poiché sembrerebbe esattamente lo stesso di una stringa.

Come funziona

+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

1

JavaScript, 214 199 byte

Come sempre: risulta che questo è troppo lungo per competere, ma ora che ho finito sarebbe uno spreco non postare questo.

Forse c'è un modo ovvio per giocare a golf così lontano che ho trascurato?

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 per casi di test


1
Che ne dici di passare fa 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:''))? Inoltre, un singolo argomento stringa può essere passato a una funzione in questo modo:s.indexOf`lv`
ETHproductions

@ETHproductions È fantastico, grazie! Non sapevo che JS avesse un operatore virgola e anche la scorciatoia per il passaggio delle stringhe è davvero utile.
vvye,

1

Perl, 158 byte

@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

Viene eseguito dalla riga di comando. one hundreddeve essere inserito "one hundred"per impedirne l'interpretazione come due ingressi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.