İngilizceyi bir sayıya çevir [kapalı]


27

Zorluğun kısa ve tatlı açıklaması:

Bu sitedeki diğer birkaç sorunun fikrinden yola çıkarak, zorluk, en yaratıcı kodu, İngilizce olarak yazılmış bir sayı girilen ve tam sayı biçimine dönüştüren herhangi bir programda yazmaktır.

Gerçekten kuru, uzun ve ayrıntılı özellikler:

  • Programınız küçük harflerle İngilizce arasında zerove dahilinde bir tamsayı girişi olarak alır nine hundred ninety-nine thousand nine hundred ninety-nine.
  • Bu arasına sayının çıkışı sadece tamsayı formu gerekir 0ve 999999ve başka bir şey (herhangi bir boşluk).
  • Giriş olacak DEĞİL ihtiva ,ya andolduğu gibi one thousand, two hundredya da five hundred and thirty-two.
  • Onlarca ve bir yerler hem sıfır olmazsa hem de onlarca yer daha büyükse 1, -boşluk yerine HYPHEN-MINUS karakteriyle ayrılırlar . On binlerce ve binlerce yer için aynı şey. Örneğin, six hundred fifty-four thousand three hundred twenty-one.
  • Program başka herhangi bir giriş için tanımsız davranışa sahip olabilir.

İyi niyetli bir programın bazı örnekleri:

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


Bu, özellikle yaratıcı değildir ve buradaki spesifikasyonla tam olarak eşleşmez, ancak başlangıç ​​noktası olarak yararlı olabilir: github.com/ghewgill/text2num/blob/master/text2num.py
Greg Hewgill

Bu soruya neredeyse cevabımı gönderebilirim .
grc

Karmaşık dize ayrıştırma neden? pastebin.com/WyXevnxb
blutorange

1
Bu arada, bu sorunun cevabı olan bir IOCCC girişi gördüm .
Snack

2
"Dört yirmi" gibi şeyler?
kabarık

Yanıtlar:


93

applescript

Bazı Cupertino / Mountain View milletini kızdırabilecek aptalca, sahte bir karmaşa , ama bence bu aptalca, sahte bir karmaşa.

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

Metin numarasını konuşmak için konuşmaya OSX metni, onu dinlemek ve bir tamsayıya dönüştürmek için google sesle arama özelliğini kullanır.

Gereksinimler

  • OSX
  • Google Chrome
  • google hesabınızda konuşma tanıma özelliği etkin
  • hacim makul bir düzeye çıktı

Gecikme zamanlamalarının, krom yükleme sürenize ve google arama sürenize bağlı olarak ayarlanması gerekebilir.

Örnek giriş:

görüntü tanımını buraya girin

Örnek çıktı:

görüntü tanımını buraya girin


13
Bunun sadece biraz yaratıcı olabileceğini düşünüyorum ...;)
Abraham

5
Lol, bu cool'in olduğunu
justhalf

2
Belki çok yaratıcı.
Cheezey

Bir hafta sonra, cevabınız açıkça 74 oyla önderlik ediyor, yani bence demek ki ... siz kazandınız! Bu arada, bu kodu kullanırsam sorun olur mu? Şu an üzerinde çalıştığım birçok gerçek dünya projesi için gerçekten yararlı olacak! ;)
Abraham,

3
@Abraham Teşekkürler! Bunu üretim kodunda kullanma konusunda şaka yapıyorsun, değil mi?
Digital Trauma

34

Bash, 93 64 55 karakter *

bsd-gamesÇoğu Linux işletim sisteminde bulunan fantastik pakette, adı verilen küçük bir komut satırı oyuncağı vardır number. Sayıları İngilizce metne çevirir, yani bu sorunun tam tersini yapar. Gerçekten tam tersi: sorudaki tüm kuralları takip ediyor number. Tesadüf olmak için neredeyse çok iyi.

$ number 42
forty-two.

Tabii ki, numbersoruyu cevaplamıyor. Başka yoldan istiyoruz. Bunu bir süre düşündüm, string ayrıştırmayı denedim ve hepsini yaptım, sonra number999.999 numaraların hepsini arayabileceğimi ve girdiyle uyuşup uyuşmadığını görebildiğimi fark ettim . Öyleyse, eşleştiği ilk satır, aradığım satır numarasının iki katıdır ( numberher sayıdan sonra bir nokta çizgisi yazdırır). Bu kadar basit. Yani, daha fazla uzatmadan, işte girişimin tam kodu:

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

Kısa devreler bile var, yani "iki" yi dönüştürmek oldukça hızlı ve daha yüksek sayılar genellikle kutumdaki bir saniyenin altında çözülüyor. İşte bir örnek çalışma:

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

Elbette, numberbunun çalışması için yüklemiş olmanız gerekir .


*: Evet, biliyorum, bu bir code-golfmeydan okuma değil , ama kısalık benim girişimin tek belirleyici niteliği.


8
+1. Benim için, numbertersini kullanmak bu cevapla ilgili en yaratıcı şey. Golfiness de olsa :) :)
Dijital Travma

1
Bu aslında oldukça yaratıcı! Bunu sevdim!
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());

Biraz sever eval()misin?

Bu betiği tarayıcınızın konsolunda çalıştırın.

Düzenleme: Geri bildiriminiz için teşekkür ederiz. Hatalar düzeltildi (tekrar).


gerçekten güzel kod ^^
zsitro

2
"Yüz on altı" gibi bir şey yazdığınızda, 126.
scrblnrd3

Bu program, twelvedöndüğünde başlayan bazı numaralar için başarısız olur 23.
Abraham

Başarısız "twenty".
200_success

seven thousand three hundred thirty fivever10335
Bebek

7

piton

Sadece topu yuvarlamak için.

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

5

Perl + CPAN

Zaten yapıldığında neden tekerleği yeniden icat ettin?

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

say words2nums $_ while <>;

Bu program, standart girdiden (ya da komut satırı argümanları olarak belirtilen bir ya da daha fazla dosyadan), her satıra bir tane olmak üzere İngilizce dizeleri okur ve karşılık gelen sayıları standart çıktıya yazdırır.

Bu kodu hem testten çıkarılan örnek girdiler hem de bsd-games numberprogramı (teşekkürler, Wander Nauta!) Kullanılarak metne dönüştürülmüş sayılardan oluşan ayrıntılı bir test paketi kullanarak test ettim ve doğru şekilde ayrıştırdı. hepsi. Ek olarak, bu aynı zamanda, örneğin, örneğin giriş anlar minus seven(-7), four and twenty(24), four score and seven(87), one gross(144), a baker's dozen(13), eleventy-one(111) ve googol(10 , 100 ).

( Not: Perl yorumlayıcısının kendisine ek olarak, bu program ayrıca CPAN modülü Lingua :: EN :: Words2Nums gerektirir . İşte CPAN modüllerini kurmak için bazı talimatlar vardır . Debian / Ubuntu Linux kullanıcıları bu modülü APT paket yöneticisi aracılığıyla da kurabilirler. olarak liblingua-en-words2nums-perl .)


4

piton

Geçerlilik kontrolü ile genel özyinelemeli bir çözüm. Gerekli sayı aralığı için basitleştirilebilir, ancak burada sanırım gösteriliyor:

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)

2

VBScript 474

Bu oldukça rutin bir cevap ... maalesef, @Snack hemen hemen aynı işlemi ancak benden önce gönderdi ki rutin.

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)

1

Haskell

Diğer özyinelemeli çözümlere benzer sanırım, ancak bunu temizlemek için zaman harcadım.

İşte tüm açıklamaların yer aldığı tam kaynak: 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

0

Ortak Lisp, 94

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

Metin dönüştürme sayısı CL'ye yerleşiktir, ancak tersi olmaz. Sayılar için ters bir eşleme oluşturur ve üzerindeki girişi kontrol eder.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.