Перетворення англійської мови на номер без вбудованих або бібліотек


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

Програма golfed обчислює 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``, перетворити на номер з одинаком +, і ми закінчили.


Будь ласка, поясніть.
Боб

@Bob Звичайно, пояснення додано.
ETHproductions

Не .findIndex(y=>x.match(y))працює?
Ніл

@Neil Я не здогадувався про це, але це, дякую!
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"; " lv "у 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("-"))))

В основному ідентичний відповіді Піта.


Не по темі:

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


Я вважаю, що ви можете зберегти сім байтів, використовуючи запакований рядок . Скопіюйте вихід і поставте його замість "ontwthfofisiseeiniteel"цієї програми.
ETHproductions

@ETHproductions Нічого, дякую! Востаннє, коли я перевіряв, на голові струни все ще було "зе", і упаковка не могла працювати. Я не перевірив ще раз після того, як гольфував це. Знову дякую xD
busukxuan

@ETHproductions так, що я насправді робив, це під псевдокодом.
busukxuan

2

Пітон 3, 365 361 310 303 символів

Гольф

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

Безумовно

 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()безпосередньо на нього.
манатура

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(",").
манатура

Двигун сайту StackExchange має дратівливу звичку: він вставляє невидимі символи (U200C Zero Width Non-Joiner та U200B Zero Width Space) у код, розміщений у коментарях. Ви також копіюєте їх. Я відредагував вашу публікацію, щоб видалити їх.
манатура

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, інакше він поверне індекс.

Безумовно

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

Пітон 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

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 для тестових випадків


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 є оператор з комами, і стенограма для передачі рядків також дуже корисна.
vvye

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"щоб перешкоджати інтерпретації як два входи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.