Konversi Bahasa Inggris ke angka [ditutup]

27

Deskripsi tantangan yang singkat dan manis:

Berdasarkan ide dari beberapa pertanyaan lain di situs ini, tantangan Anda adalah menulis kode paling kreatif dalam program apa pun yang mengambil input angka yang ditulis dalam bahasa Inggris dan mengubahnya menjadi bentuk integer.

Spesifikasi benar-benar kering, panjang dan menyeluruh:

  • Program Anda akan menerima input bilangan bulat dalam bahasa Inggris kecil antara zerodan nine hundred ninety-nine thousand nine hundred ninety-nineinklusif.
  • Ini harus menampilkan hanya bentuk bilangan bulat antara 0dan 999999dan tidak ada yang lain (tanpa spasi).
  • Input TIDAK akan berisi ,atau and, seperti pada one thousand, two hundredatau five hundred and thirty-two.
  • Ketika puluhan dan satu tempat sama-sama bukan nol dan puluhan tempat lebih besar dari 1, mereka akan dipisahkan oleh karakter HYPHEN-MINUS -bukannya spasi. Ditto untuk sepuluh ribu dan ribuan tempat. Sebagai contoh six hundred fifty-four thousand three hundred twenty-one,.
  • Program mungkin memiliki perilaku yang tidak ditentukan untuk input lainnya.

Beberapa contoh program yang berperilaku baik:

zero-> 0
fifteen-> 15
ninety-> 90
seven hundred four-> 704
sixty-nine thousand four hundred eleven-> 69411
five hundred twenty thousand two->520002

Abraham
sumber
Ini tidak terlalu kreatif, juga tidak cocok dengan spesifikasi di sini, tetapi mungkin berguna sebagai titik awal: github.com/ghewgill/text2num/blob/master/text2num.py
Greg Hewgill
Saya hampir bisa memposting jawaban saya untuk pertanyaan ini .
grc
Mengapa parsing string yang rumit? pastebin.com/WyXevnxb
blutorange
1
Omong-omong, saya melihat entri IOCCC yang merupakan jawaban dari pertanyaan ini.
Snack
2
Bagaimana dengan hal-hal seperti "empat dan dua puluh?"
fluffy

Jawaban:

93

Applescript

Mash-up konyol dan konyol yang mungkin membuat marah beberapa orang Cupertino / Mountain View, tapi saya pikir ini kreatif, konyol mash-up.

set myNumber to text returned of (display dialog ¬
    "Enter number as text:" buttons {"Continue…"} ¬
    default answer "" default button 1)
tell application "Google Chrome"
    activate
    open location "https://www.google.com"
end tell
delay 5
say "ok google. " & myNumber
delay 2
tell application "System Events"
    tell application process "Google Chrome"
        set fullURL to value of text field 1 of toolbar 1 of window 1
    end tell
end tell
set AppleScript's text item delimiters to "="
display alert item 2 of text items of fullURL

Menggunakan teks OSX untuk berbicara untuk mengucapkan nomor teks, dan pencarian audio google untuk mendengarkannya dan mengubahnya menjadi bilangan bulat.

Persyaratan

  • OSX
  • Google chrome
  • pengenalan ucapan diaktifkan di akun google Anda
  • volume naik ke tingkat yang wajar

Timing waktu mungkin perlu disesuaikan tergantung pada waktu buka krom Anda dan waktu pencarian google.

Input contoh:

masukkan deskripsi gambar di sini

Contoh output:

masukkan deskripsi gambar di sini

Trauma Digital
sumber
13
Saya pikir itu mungkin hanya sedikit kreatif ...;)
Abraham
5
Lol, ini keren
justhalf
2
Mungkin terlalu kreatif.
Cheezey
Setelah satu minggu, jawaban Anda jelas memimpin di 74 suara, jadi saya pikir itu berarti .. Anda menang! Omong-omong, keberatan jika saya menggunakan kode ini? Ini akan sangat berguna untuk banyak proyek dunia nyata yang saya kerjakan sekarang! ;)
Abraham
3
@Abraham Terima kasih! Anda bercanda tentang menggunakan ini dalam kode produksi, kan?
Digital Trauma
34

Bash, 93 64 55 karakter *

Dalam bsd-gamespaket fantastis yang tersedia di sebagian besar sistem operasi Linux, ada mainan command-line kecil bernama number. Itu mengubah angka menjadi teks bahasa Inggris, yaitu, ia melakukan kebalikan dari pertanyaan ini. Ini benar-benar kebalikannya: semua aturan dalam pertanyaan diikuti oleh number. Hampir terlalu bagus untuk menjadi kebetulan.

$ number 42
forty-two.

Tentu saja, numbertidak menjawab pertanyaan itu. Kami ingin sebaliknya. Saya memikirkan hal ini sebentar, mencoba string parsing dan semua itu, kemudian menyadari bahwa saya bisa memanggil numbersemua nomor 999.999 dan melihat apakah ada sesuatu yang cocok dengan input. Jika demikian, baris pertama yang cocok memiliki dua kali jumlah baris yang saya cari ( numbermencetak garis titik setelah setiap angka). Sederhana seperti itu. Jadi, tanpa basa-basi lagi, inilah kode lengkap untuk entri saya:

seq 0 999999|number -l|awk "/$1/{print (NR-1)/2;exit}"

Bahkan sirkuit pendek, sehingga mengkonversi "dua" cukup cepat, dan bahkan angka yang lebih tinggi biasanya diterjemahkan dalam waktu kurang dari satu detik di kotak saya. Berikut ini contoh yang dijalankan:

wn@box /tmp> bash unnumber.sh "zero"
0
wn@box /tmp> bash unnumber.sh "fifteen"
15
wn@box /tmp> bash unnumber.sh "ninety" 
90
wn@box /tmp> bash unnumber.sh "seven hundred four"
704
wn@box /tmp> bash unnumber.sh "sixty-nine thousand four hundred eleven"
69411
wn@box /tmp> bash unnumber.sh "five hundred twenty thousand two"    
520002

Tentu saja, Anda harus sudah numbermenginstal agar ini berfungsi.


*: Ya, saya tahu, ini bukan code-golftantangan, tapi kekurangannya adalah satu-satunya kualitas dari entri saya, jadi ... :)

Mengembara Nauta
sumber
8
+1. Bagi saya, menggunakan numbersecara terbalik adalah hal paling kreatif tentang jawaban ini. Golfinessnya juga bagus :)
Digital Trauma
1
Ini sebenarnya cukup kreatif! Saya suka itu!
sokie
13

Javascript

(function parse(input) {
  var pat = "ze/on/tw/th.?r/fo/fi/ix/se/ei/ni/ten/ele".split("/");
  var num = "", last = 0, token = input.replace(/-/g, " ").split(" ");
  for(var i in token) {
    var t = token[i];
    for(var p in pat) if(t.match(RegExp(pat[p])) !== null) num += "+" + p;
    if(t.indexOf("een") >= 0) num += "+10";
    if(t.indexOf("lve") >= 0) num += "+10";
    if(t.indexOf("ty") >= 0) num += "*10";
    if(t.indexOf("dr") >= 0) { last = 100; num += "*100"; }
    if(t.indexOf("us") >= 0) {
      if(last < 1000) num = "(" + num + ")"; last = 0;
      num += "*1000";
    }
  }
  alert(eval(num));
})(prompt());

Apakah kamu menyukai beberapa eval()?

Jalankan skrip ini di konsol browser Anda.

Sunting: Terima kasih atas umpan baliknya. Bug diperbaiki (lagi).

Camilan
sumber
kode yang sangat bagus ^^
zsitro
2
Ketika Anda mengetikkan sesuatu seperti "seratus enam belas", itu akan menghasilkan 126.
scrblnrd3
Program ini gagal untuk beberapa angka mulai twelvesaat kembali 23.
Abraham
Gagal aktif "twenty".
200_success
seven thousand three hundred thirty fiveberi aku10335
Bayi
7

Python

Hanya untuk membuat bola bergulir.

import re
table = {'zero':0,'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,'thirty':30,'forty':40,'fifty':50,'sixty':60,'ninety':90}
modifier = {'hundred':100,'thousand':1000}

while True:
    text = raw_input()
    result = 0
    tmp = 0
    last_multiplier = 1
    for word in re.split('[- ]', text):
        multiplier = modifier.get(word, 1)
        if multiplier > last_multiplier:
            result = (result+tmp)*multiplier
            tmp = 0
        else:
            tmp *= multiplier
        if multiplier != 1:
            last_multiplier = multiplier
        tmp += table.get(word,0)
    print result+tmp
justhalf
sumber
5

Perl + CPAN

Mengapa menemukan kembali roda, ketika sudah dilakukan?

use feature 'say';
use Lingua::EN::Words2Nums;

say words2nums $_ while <>;

Program ini membaca string bahasa Inggris dari input standar (atau dari satu atau lebih file yang ditentukan sebagai argumen baris perintah), satu per baris, dan mencetak angka yang sesuai ke output standar.

Saya telah menguji kode ini menggunakan input sampel dari tantangan, dan juga paket uji lengkap yang terdiri dari angka 0 hingga 999999 yang dikonversi ke teks menggunakan numberutilitas bsd-games (terima kasih, Mengembara Nauta!), Dan kode ini mengurai dengan benar mereka semua. Sebagai bonus, ia juga memahami input seperti misalnya minus seven(−7), four and twenty(24), four score and seven(87), one gross(144), a baker's dozen(13), eleventy-one(111) dan googol(10 100 ).

( Catatan: Selain interpreter Perl itu sendiri, program ini juga memerlukan modul CPAN Lingua :: EN :: Words2Nums . Berikut adalah beberapa instruksi untuk menginstal modul CPAN . Pengguna Debian / Ubuntu Linux juga dapat menginstal modul ini melalui manajer paket APT sebagai liblingua-en-words2nums-perl .)

Ilmari Karonen
sumber
4

Python

Solusi rekursif umum, dengan pemeriksaan validitas. Bisa disederhanakan untuk rentang angka yang diperlukan, tapi di sini untuk pamer, saya kira:

terms = 'zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen'.split()
tee  = 'twenty thirty forty fifty sixty seventy eighty ninety'.split()
for t in tee:
    terms.append(t)
    for s in terms[1:10]:
        terms.append(t+'-'+s)

terms = dict(zip(terms, range(100)))

modifiers = [('hundred', 100), ('thousand', 1000), ('million', 10**6), ('billion', 10**9)]

def read_num(words):
    if len(words) == 0: return 0
    elif len(words) == 1:
        if words[0] in terms:
            return terms[words[0]]
        else:
            raise ValueError(words[0]+' is not a valid english number.')
    else:
        for word, value in reversed(modifiers):
            if word in words:
                i = words.index(word)
                return read_num(words[:i])*value+read_num(words[i+1:])

    raise ValueError(' '.join(words)+' is not a valid english number.')

while True:
    try:
        print(read_num(input().split()))
    except ValueError as e:
        print(e)
CesiumLifeJacket
sumber
2

VBScript 474

Ini adalah jawaban yang cukup rutin ... sayangnya, sangat rutin sehingga @Snack cukup banyak memposting proses yang sama tetapi sebelum saya.

i=split(REPLACE(REPLACE(inputbox(""),"lve","een"),"tho","k"))
o=split("z on tw th fo fi si se ei ni ten ele")
y=split("red *100) k )*1000 ty *10) een +10)")
z=""
p=0
for t=0 to UBOUND(i)
    s=split(i(t),"-")
    u=ubound(s)
    r=s(0)
    for x=0 to UBOUND(o)    
        IF INSTR(r,o(x)) THEN
            z=z+"+"+CSTR(x)
        END IF
        IF u Then
            IF INSTR(s(1),o(x)) THEN
                z=z+CSTR(x)
            END IF
        END IF
    next
    for m=0 to UBOUND(y)
        IF INSTR(r,y(m))AND u=0 THEN
            z=z+y(m+1)
            p=p+1
        END IF
    next
next
Execute("MSGBOX "+String(p,"(")+z)
nyaman
sumber
1

Haskell

Mirip dengan solusi rekursif lainnya, saya rasa, tetapi saya mengambil waktu untuk membuatnya bersih.

Berikut adalah sumber lengkap dengan semua penjelasan: http://ideone.com/fc8zcB

-- Define a type for a parser from a list of tokens to the value they represent.
type NParse = [Token] -> Int    

-- Map of literal tokens (0-9, 11-19 and tens) to their names.
literals = [
        ("zero", 0), ("one", 1), ("two", 2), ("three", 3), ("four", 4), ("five", 5), ("six", 6), ("seven", 7), ("eight", 8), ("nine", 9),
        ("eleven", 11), ("twelve", 12), ("thirteen", 13), ("fourteen", 14), ("fifteen", 15), ("sixteen", 16), ("seventeen", 17), ("eighteen", 18), ("nineteen", 19),
        ("ten", 10), ("twenty", 20), ("thirty", 30), ("fourty", 40), ("fifty", 50), ("sixty", 60), ("seventy", 70), ("eighty", 80), ("ninety", 90)
    ]

-- Splits the input string into tokens.
-- We do one special transformation: replace dshes by a new token. Such that "fifty-three" becomes "fifty tens three". 
prepare :: String -> [Token]

-- Let's do the easy stuff and just parse literals first. We just have to look them up in the literals map.
-- This is our base parser.
parseL :: NParse
parseL [tok] = case lookup tok literals of 
    Just x -> x

-- We're going to exploit the fact that the input strings have a tree-like structure like so
--                    thousand
--          hundred             hundred
--      ten       ten       ten         ten
--    lit   lit lit  lit   lit  lit    lit  lit
-- And recursively parse that tree until we only have literal values.
--
-- When parsing the tree
--       thousand
--     h1       h2
-- The resulting value is 1000 * h1 + h2.
-- And this works similarly for all levels of the tree.
-- So instead of writing specific parsers for all levels, let's just write a generic one :

{- genParse :: 
    NParse      : the sub parser
    -> Int      : the left part multiplier
    -> Token    : the boundary token 
    -> NParse   : returns a new parser -}   
genParse :: NParse -> Int -> Token -> NParse    
genParse delegate mul tok = newParser where
    newParser [] = 0
    newParser str = case splitAround str tok of
        -- Split around the boundary token, sub-parse the left and right parts, and combine them
        (l,r) -> (delegate l) * mul + (delegate r)  

-- And so here's the result: 
parseNumber :: String -> Int
parseNumber = parseM . prepare
    where   -- Here are all intermediary parsers for each level
    parseT = genParse   parseL  1       "tens"       -- multiplier is irregular, because the fifty in fifty-three is already multiplied by 10
    parseH = genParse   parseT  100     "hundred"
    parseK = genParse   parseH  1000    "thousand"
    parseM = genParse   parseK  1000000 "million" -- For fun :D

test = (parseNumber "five hundred twenty-three thousand six hundred twelve million two thousand one") == 523612002001
ARRG
sumber
0

Common Lisp, 94

(write(cdr(assoc(read-line)(loop for i to 999999 collect(cons(format()"~r"i)i)):test #'equalp)))

Konversi angka ke teks dibangun untuk CL, tetapi tidak sebaliknya. Buat pemetaan terbalik untuk angka-angka dan periksa input di atasnya.

Harry
sumber