Конвертировать английский в число без встроенных модулей или библиотек

14

Эта задача аналогична другой , однако я наложил ограничение (см. Жирный текст ниже), которое, я думаю, сделало бы его гораздо более разнообразным и (я надеюсь) веселым.

Соревнование

Напишите программу или функцию на любом языке программирования, которая принимает в качестве входных данных английское имя положительного целого числа, nне превышающего, 100и возвращает его nкак целое число.

Стандартные лазейки запрещены, и вы не можете использовать любую встроенную функцию, внешний инструмент или библиотеку, которая уже выполняет эту работу .

Самый короткий исходный код в байтах побеждает.

Тестовое задание

Здесь все input->outputдела:

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
А как насчет встроенного, который выполняет половину работы, например, поиск юникод-имени кодовой точки.
Брэд Гилберт b2gills
@ BradGilbertb2gills Нет, это не хорошо.
Боб

Ответы:

22

C 160 байт

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

Проверь это

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

Как это устроено

После нескольких попыток, я нашел функцию , которая отображает "исключительное" число 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, для печатаемых символов ASCII k, ., [, <, *, , c, K, w, y, e, (, S, _, -, C, ), 7, =, 4, &,o, ], s, Y, g, m, N, Соответственно.

Эта функция:

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

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

    return r%45+77;
}

Программа для игры в гольф вычисляет hashфункцию ввода, пока не достигнет конца строки или символа -. Затем он ищет хеш в строке k.[<* cKwye(S_-C)7=4&o]sYgmNи определяет соответствующий номер. Если достигнут конец входной строки, возвращается число, если вместо него -был достигнут а, то возвращается номер плюс результат программы гольфа, примененной к остальной части входной строки.

боб
источник
Я думаю, что если бы была версия C для игры в гольф, она могла бы побить такие языки, как CJam Pyth Japt и т. Д.
busukxuan
11

JavaScript (ES6), 175 166 163 156 153 147 байт

Сохранено 7 байтов благодаря @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``

Проверьте это здесь:

Как это устроено

Основная идея состоит в том, чтобы разбить каждое число на его цифры-слова, а затем сопоставить каждое слово с соответствующей цифрой. Почти все слова настроены так, чтобы соответствовать обычному регулярному выражению, но есть несколько аномалий:

  • elevenчерез nineteen: если слово содержит el, или teв середине (чтобы избежать ten), мы добавляем on-в начало, изменяя их на on-elevenсквознойon-nineteen .
  • twenty, thirtyИ т.д .: замена завершающую yс -dизменением их к twent-d, thirt-dи т.д.

Теперь мы разбиваем дефисы, пробелы и drs. Это расколы все от 11 до 99 в его соответствующих цифрах-слова, и "one hundred"в [one,hun,ed]. Затем мы отображаем каждое из этих слов через массив регулярных выражений и сохраняем индекс того, который соответствует первому.

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.

К настоящему времени каждый вход будет массивом правильных цифр. Все, что нам нужно сделать, это присоединиться к ним join``, преобразовать в число с унарным +, и все готово.

ETHproductions
источник
Пожалуйста, объясни.
Боб
@ Боб Конечно, объяснение добавлено.
ETHproductions
Не .findIndex(y=>x.match(y))работает?
Нил
@ Нил, я не понимал, что так, но это так, спасибо!
ETHproductions
Я уверен, что вы можете использовать псевдоним replace.
Mama Fun Roll
6

sh + coreutils, 112 байт

Может быть запущен на всех тестовых примерах, по одному на строку.

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

объяснение

Обратная пометка awkоценивает sedсценарий

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

который превращает части чисел в их числовое представление.

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

Дополнительные строки сценария sed

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

заботиться о -tyс и one hundred.

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

Наконец, удалите начальные +s и все, что не является +, *или цифру.

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

Остаются только математические выражения

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

и может быть по трубопроводу bc.

Райнер П.
источник
4

Пиф, 79 76 75 68 байт

Спасибо @ETHproductions за 7 байтов.

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

В основном сначала проверяется угловой регистр 100, затем используется массив первых двух букв чисел от 0 до 11, чтобы определить семантику ввода и изменить значение в соответствии с суффиксом ("-ty" и "-teen"; " лв "в 12 это еще один угловой случай). Сначала разбивает входные данные на список слов, затем сопоставляет каждое из них со значением и суммирует их.

В питоническом псевдокоде:

                           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

Тестирование


Python 3, 218 байт

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

В основном идентичный ответу Pyth.


Не по теме:

Я только что обнаружил значимую версию ответа на жизнь, вселенную и все остальное: это жаждущие чая веточки. Вау, веточки, которые жаждут чая! Я не уверен, сколько других ответов делают это, но для моего ответа, если ввод "чай-жажду прутьев", вывод 42.

busukxuan
источник
Я считаю, что вы можете сохранить семь байтов, используя упакованную строку . Скопируйте вывод и поместите его вместо "ontwthfofisiseeiniteel"этой программы.
ETHproductions
@ETHproductions Вау, спасибо! В прошлый раз, когда я проверял, все еще было «зе» в начале строки, и упаковка не могла работать. Я не проверял еще раз после того, как играл в гольф.
Еще
@ETHproductions да, я на самом деле сделал, это под псевдокодом.
Busukxuan
2

Python 3, 365 361 310 303 символов

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 символов короче: 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(",")но, как я вижу, должно работать, не назначая его переменной n, просто вызовите его .index()напрямую.
manatwork
7 символов короче: "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
У движка сайта StackExchange есть раздражающая привычка: он вставляет невидимые символы (U200C Zero Width Non-Joiner и U200B Zero Width Space) в код, размещенный в комментариях. Ты их тоже скопировал. Я отредактировал твой пост, чтобы удалить их.
manatwork
2

Haskell, 252 231 байт

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

Это создает список всех английских имен чисел от «один» до «девяносто девять», а затем просматривает индекс ввода вверх. Если его не существует, мы находимся в крайнем случае «сто», поэтому он возвращает 100, в противном случае он собирается вернуть индекс.

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
источник
2

Python 2, 275 символов

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

Он просто строит список каждого числа и находит индекс.

Питер
источник
1

Japt, 82 байта

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

Каждый ¿представляет непечатаемый символ. Проверьте это онлайн!

На основании моего ответа JS. Вычтите один байт, если вывод не должен быть целым числом, так как он будет выглядеть точно так же, как строка.

Как это устроено

+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
источник
1

JavaScript, 214 199 байт

Как всегда: оказывается, это слишком долго, чтобы соревноваться, но теперь, когда я закончил, было бы бесполезно не публиковать это.

Возможно, есть еще один очевидный способ игры в гольф, который я упустил из виду?

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 для тестовых случаев

vvye
источник
1
Как насчет перехода fна 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:''))? Кроме того, один строковый аргумент может быть передан функции, например, так:s.indexOf`lv`
ETHproductions
@ETHproductions Это здорово, спасибо! Я не знал, что у JS есть оператор запятой, и сокращение для передачи строки также очень полезно.
ввь
1

Perl, 158 байт

@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

Запускается из командной строки. one hundredдолжен быть введен так, "one hundred"чтобы остановить его как два входа.

CJ Деннис
источник