Convertir l'anglais en un nombre sans fonctions intégrées ni bibliothèques

14

Ce défi est similaire à cet autre , mais j'ai fait une restriction (voir le texte en gras ci-dessous) qui, je pense, le rendrait très différent et (j'espère) amusant aussi.

Le défi

Écrivez un programme ou une fonction dans n'importe quel langage de programmation qui prend en entrée le nom anglais d'un entier positif nne dépassant pas 100et retourne ncomme un entier.

Les failles standard sont interdites et vous ne pouvez pas utiliser de fonction intégrée, d'outil externe ou de bibliothèque qui fait déjà ce travail .

Le code source le plus court en octets gagne.

Tester

Voici tous les input->outputcas:

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
Bob
la source
1
Qu'en est-il d'un intégré qui fait la moitié du travail, par exemple trouver le nom unicode d'un point de code.
Brad Gilbert b2gills
@ BradGilbertb2gills Non, ce n'est pas bien.
Bob

Réponses:

22

C, 160 octets

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

Essaye-le

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

Comment ça fonctionne

Après quelques tentatives, j'ai trouvé une fonction qui les numéros "exceptionnels" 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, aux caractères ASCII imprimables k, ., [, <, *, , c, K, w, y, e, (, S, _, -, C, ), 7, =, 4, &,o, ], s, Y, g, m, NRespectivement.

Cette fonction est:

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

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

    return r%45+77;
}

Le programme golfé calcule la hashfonction de l'entrée jusqu'à ce qu'il atteigne la fin de la chaîne ou du caractère -. Il recherche ensuite le hachage dans la chaîne k.[<* cKwye(S_-C)7=4&o]sYgmNet détermine le nombre correspondant. Si la fin de la chaîne d'entrée a été atteinte, le nombre est renvoyé, si à la place un a -été atteint, alors il est renvoyé le nombre plus le résultat du programme joué appliqué au reste de la chaîne d'entrée.

Bob
la source
Je pense que s'il y avait une version golfique de C, elle pourrait en fait battre des langages comme CJam Pyth Japt etc ...
busukxuan
11

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

7 octets enregistrés grâce à @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``

Vérifiez-le ici:

Comment ça fonctionne

L'idée de base est de diviser chaque nombre en ses mots numériques, puis de mapper chaque mot au chiffre correspondant. Presque tous les mots sont configurés pour correspondre correctement à une simple expression régulière, mais il y a quelques anomalies:

  • eleventhrough nineteen: si le mot contient un el, ou un teau milieu (pour éviter ten), nous ajoutons un on-au début, en les changeant en on-eleventhrough on-nineteen.
  • twenty, thirty, Etc .: le remplacement d' une fuite yavec les -dchangements à ceux - ci twent-d, thirt-detc.

Nous séparons maintenant les traits d'union, les espaces et les drs. Cela divise tout de 11 à 99 en ses mots numériques correspondants, et "one hundred"en [one,hun,ed]. Ensuite, nous mappons chacun de ces mots à travers un tableau d'expressions régulières, et gardons l'index de celui qui correspond en premier.

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.

À ce jour, chaque entrée sera le tableau des bons chiffres. Tout ce que nous avons à faire est de les rejoindre join``, de les convertir en nombre avec unaire +, et nous avons terminé.

ETHproductions
la source
S'il vous plaît, expliquez.
Bob
@Bob Bien sûr, explication ajoutée.
ETHproductions
Ça ne .findIndex(y=>x.match(y))marche pas ?
Neil
@Neil Je ne m'en rendais pas compte, mais c'est le cas, merci!
ETHproductions
Je suis sûr que vous pouvez alias replace.
Mama Fun Roll
6

sh + coreutils, 112 octets

Peut être exécuté sur tous les cas de test à la fois, un par ligne.

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

Explication

Le backticked awkévalue le 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

qui transforme des parties de nombres en leur représentation numérique.

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

Les lignes supplémentaires du script sed

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

prendre soin de -tys et one hundred.

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

Enfin, supprimez les +s en tête et tout ce qui ne l'est pas +, *ou un chiffre.

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

Seules les expressions mathématiques restent

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

et peut être canalisé bc.

Rainer P.
la source
4

Pyth, 79 76 75 68 octets

Merci @ETHproductions pour 7 octets.

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

Fondamentalement, vérifie d'abord le cas de coin de 100, puis utilise un tableau des deux premières lettres des chiffres 0 à 11 pour déterminer la sémantique de l'entrée et modifier la valeur en fonction du suffixe ("-ty" et "-teen"; " lv "dans 12 est un autre cas d'angle). Divise d'abord l'entrée en une liste de mots, puis mappez chacun à une valeur et résumez-les.

En pseudocode pythonique:

                           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 de tests


Python 3, 218 octets

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

Fondamentalement identique à la réponse Pyth.


Hors sujet:

Je viens de découvrir une version significative de la réponse à la vie, à l'univers et à tout: ce sont des brindilles assoiffées de thé. Wow, des brindilles qui aspirent au thé! Je ne sais pas combien d'autres réponses font cela, mais pour ma réponse si l'entrée est "brindilles assoiffées de thé", la sortie est 42.

busukxuan
la source
Je crois que vous pouvez économiser sept octets en utilisant une chaîne compressée . Copiez la sortie et mettez-la à la place de "ontwthfofisiseeiniteel"ce programme.
ETHproductions
@ETHproductions Wow, merci! La dernière fois que j'ai vérifié, il y avait toujours "ze" à la tête de la chaîne, et l'emballage ne pouvait pas fonctionner. Je n'ai pas vérifié une fois de plus après l'avoir joué au golf. Encore une fois, merci xD
busukxuan
@ETHproductions oui je l'ai fait, c'est sous le pseudocode.
busukxuan
2

Python 3, 365 361 310 303 caractères

Golfé

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

Non golfé

 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
la source
45 caractères plus court: 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(",")Mais comme je le vois, devrait fonctionner sans l'assigner à la variable n, il suffit d'appeler .index()directement dessus.
manatwork
7 caractères plus courts: "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
Le moteur du site StackExchange a une habitude irritante: il insère des caractères invisibles (U200C Zero Width Non-Joiner et U200B Zero Width Space) dans le code publié dans les commentaires. Vous les avez également copiés-collés. J'ai modifié votre message pour les supprimer.
manatwork
2

Haskell, 252 231 octets

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

Cela crée une liste de tous les noms de nombres anglais de "un" à "quatre-vingt-dix-neuf", puis regarde l'index de l'entrée vers le haut. S'il n'existe pas, nous sommes dans le cas de bord "cent", donc il revient100 , sinon ça va retourner l'index.

Non golfé

-- 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
la source
2

Python 2, 275 caractères

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

Il construit simplement une liste de chaque nombre et trouve l'index.

Peter
la source
1

Japt, 82 octets

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

Chacun ¿représente un caractère non imprimable.Testez-le en ligne!

Basé sur ma réponse JS. Soustrayez un octet si la sortie n'a pas besoin d'être un entier, car elle apparaît exactement comme une chaîne.

Comment ça fonctionne

+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
la source
1

JavaScript, 214 199 octets

Comme toujours: il s'avère que c'est trop long pour concourir, mais maintenant que j'ai fini, ce serait un gaspillage de ne pas poster ça.

Peut-être y a-t-il un moyen évident de jouer au golf plus loin que j'ai négligé?

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 pour les cas de test

vvye
la source
1
Que diriez-vous de changer fpour 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:''))? De plus, un seul argument de chaîne peut être passé à une fonction comme ceci:s.indexOf`lv`
ETHproductions
@ETHproductions C'est super, merci! Je ne savais pas que JS avait un opérateur virgule, et le raccourci pour le passage de chaîne est également très utile.
vvye
1

Perl, 158 octets

@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

S'exécute à partir de la ligne de commande. one hundreddoit être entré de façon "one hundred"à ne pas être interprété comme deux entrées.

CJ Dennis
la source