Chuyển đổi tiếng Anh sang số [đã đóng]


27

Mô tả ngắn gọn và ngọt ngào về thử thách:

Dựa trên ý tưởng của một số câu hỏi khác trên trang web này, thử thách của bạn là viết mã sáng tạo nhất trong bất kỳ chương trình nào lấy đầu vào là một số được viết bằng tiếng Anh và chuyển đổi nó thành dạng số nguyên.

Thông số kỹ thuật thực sự khô, dài và kỹ lưỡng:

  • Chương trình của bạn sẽ nhận được như là một số nguyên bằng tiếng Anh viết thường giữa zeronine hundred ninety-nine thousand nine hundred ninety-ninebao gồm.
  • Nó phải ra chỉ có hình thức số nguyên của số giữa 0999999và không có gì khác (không khoảng trắng).
  • Đầu vào sẽ KHÔNG chứa ,hoặc and, như trong one thousand, two hundredhoặc five hundred and thirty-two.
  • Khi vị trí hàng chục và một vị trí đều khác không và vị trí hàng chục lớn hơn 1, chúng sẽ được phân tách bằng ký tự HYPHEN-MINUS -thay vì khoảng trắng. Ditto cho mười ngàn và hàng ngàn nơi. Ví dụ , six hundred fifty-four thousand three hundred twenty-one.
  • Chương trình có thể có hành vi không xác định cho bất kỳ đầu vào khác.

Một số ví dụ về một chương trình ứng xử tốt:

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


Điều này không đặc biệt sáng tạo, cũng không khớp chính xác với đặc điểm kỹ thuật ở đây, nhưng nó có thể hữu ích như một điểm khởi đầu: github.com/ghewgill/text2num/blob/master/text2num.py
Greg Hewgill

Tôi gần như có thể gửi câu trả lời của tôi cho câu hỏi này .
grc

Tại sao phân tích chuỗi phức tạp? pastebin.com/WyXevnxb
blutorange

1
Nhân tiện, tôi thấy một mục IOCCC là câu trả lời của câu hỏi này.
Ăn nhẹ

2
Thế còn những thứ như "bốn và hai mươi?"
lông mịn

Câu trả lời:


93

Táo

Một mash-up ngớ ngẩn, hacky có thể làm phiền một số người Cupertino / Mountain View, nhưng tôi nghĩ đó là một mash-up ngớ ngẩn, sáng tạo.

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

Sử dụng văn bản OSX thành lời nói để nói số văn bản và tìm kiếm âm thanh google để nghe và chuyển đổi nó thành một số nguyên.

Yêu cầu

  • OSX
  • Google chrome
  • nhận dạng giọng nói được kích hoạt trong tài khoản google của bạn
  • khối lượng tăng lên đến mức hợp lý

Thời gian trễ có thể cần được điều chỉnh tùy thuộc vào thời gian tải chrome và thời gian tra cứu google của bạn.

Ví dụ đầu vào:

nhập mô tả hình ảnh ở đây

Ví dụ đầu ra:

nhập mô tả hình ảnh ở đây


13
Tôi nghĩ rằng đó có thể chỉ là một chút sáng tạo ...;)
Abraham

5
Lol, điều này thật tuyệt
cần

2
Có lẽ quá sáng tạo.
Cheezey

Sau một tuần, câu trả lời của bạn rõ ràng dẫn đầu với 74 phiếu, vì vậy tôi nghĩ điều đó có nghĩa là .. bạn đã thắng! Nhân tiện, nếu tôi sử dụng mã này? Nó sẽ thực sự hữu ích cho rất nhiều dự án trong thế giới thực mà tôi đang thực hiện ngay bây giờ! ;)
Áp-ra-ham

3
@Abraham Cảm ơn! Bạn đang nói đùa về việc sử dụng điều này trong mã sản xuất, phải không?
Chấn thương kỹ thuật số

34

Bash, 93 64 55 ký tự *

Trong bsd-gamesgói tuyệt vời có sẵn trên hầu hết các hệ điều hành Linux, có một đồ chơi dòng lệnh nhỏ được gọi number. Nó biến số thành văn bản tiếng Anh, nghĩa là, nó hoàn toàn ngược lại với câu hỏi này. Nó thực sự hoàn toàn ngược lại: tất cả các quy tắc trong câu hỏi được tuân theo number. Nó gần như là quá tốt để là một sự trùng hợp ngẫu nhiên.

$ number 42
forty-two.

Tất nhiên, numberkhông trả lời câu hỏi. Chúng tôi muốn nó theo cách khác. Tôi đã suy nghĩ về điều này trong một thời gian, đã thử phân tích chuỗi và tất cả những thứ đó, sau đó nhận ra rằng tôi chỉ có thể gọi numbertrên tất cả các số 999.999 và xem có cái gì khớp với đầu vào không. Nếu vậy, dòng đầu tiên mà nó khớp có gấp đôi số dòng tôi đang tìm ( numberin một dòng dấu chấm sau mỗi số). Đơn giản như thế. Vì vậy, không có gì khó chịu, đây là mã hoàn chỉnh cho mục nhập của tôi:

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

Nó thậm chí ngắn mạch, vì vậy chuyển đổi "hai" là khá nhanh, và số thậm chí cao hơn thường được giải mã dưới một giây trên hộp của tôi. Đây là một ví dụ chạy:

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

Tất nhiên, bạn sẽ cần phải numbercài đặt để nó hoạt động.


*: Vâng, tôi biết, đây không phải là một code-golfthử thách, nhưng độ ngắn gần như là chất lượng sáng suốt duy nhất của mục nhập của tôi, vì vậy ... :)


8
+1. Đối với tôi, sử dụng numberngược lại là điều sáng tạo nhất về câu trả lời này. Khả năng chơi gôn cũng tốt :)
Chấn thương kỹ thuật số

1
Điều này thực sự khá sáng tạo! Tôi thích nó!
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());

Bạn có thích một số eval()?

Chạy tập lệnh này trên bảng điều khiển của trình duyệt của bạn.

Chỉnh sửa: Cảm ơn phản hồi. Lỗi cố định (một lần nữa).


mã thực sự tốt đẹp ^^
zsitro

2
Khi bạn gõ một cái gì đó như "một trăm mười sáu", nó sẽ cung cấp cho 126.
Scrblnrd3

Chương trình này thất bại đối với một số số bắt đầu twelvekhi nó trở lại 23.
Áp-ra-ham

Thất bại trên "twenty".
200_success

seven thousand three hundred thirty fivecho tôi10335
Em bé

7

Con trăn

Chỉ để có được quả bóng lăn.

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

Tại sao phải phát minh lại bánh xe, khi nó đã được thực hiện?

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

say words2nums $_ while <>;

Chương trình này đọc các chuỗi tiếng Anh từ đầu vào tiêu chuẩn (hoặc từ một hoặc nhiều tệp được chỉ định làm đối số dòng lệnh), mỗi chuỗi trên một dòng và in ra các số tương ứng thành đầu ra tiêu chuẩn.

Tôi đã kiểm tra mã này bằng cả hai đầu vào mẫu từ thử thách, cũng như bộ thử nghiệm toàn diện bao gồm các số từ 0 đến 999999 được chuyển đổi thành văn bản bằng numbertiện ích bsd-games (cảm ơn, Wander Nauta!) Và nó phân tích chính xác Tất cả bọn họ. Là một phần thưởng, nó cũng hiểu các đầu vào như ví dụ minus seven(−7), four and twenty(24), four score and seven(87), one gross(144), a baker's dozen(13), eleventy-one(111) và googol(10 100 ).

( Lưu ý: Ngoài chính trình thông dịch Perl, chương trình này cũng yêu cầu mô-đun CPAN Lingua :: EN :: Words2Nums . Dưới đây là một số hướng dẫn để cài đặt các mô-đun CPAN . Người dùng Debian / Ubuntu Linux cũng có thể cài đặt mô-đun này thông qua trình quản lý gói APT như liblingua-en-words2nums-perl .)


4

Con trăn

Một giải pháp đệ quy chung, với kiểm tra tính hợp lệ. Có thể được đơn giản hóa cho phạm vi số được yêu cầu, nhưng ở đây để hiển thị tôi đoán:

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

Đây là một câu trả lời khá thường xuyên ... thật không may, quá thường xuyên đến nỗi @Snack đã đăng tải quá trình tương tự nhưng trước tôi.

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

Tương tự như các giải pháp đệ quy khác tôi đoán, nhưng tôi đã dành thời gian để làm cho nó sạch sẽ.

Đây là nguồn hoàn chỉnh với tất cả các giải thích: 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

Lisp thường gặp, 94

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

Chuyển đổi số thành văn bản được tích hợp vào CL, nhưng không phải là cách khác. Xây dựng một ánh xạ ngược cho các số và kiểm tra đầu vào trên nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.