Englisch in eine Zahl umwandeln [closed]

27

Kurze und süße Beschreibung der Herausforderung:

Basierend auf den Ideen mehrerer anderer Fragen auf dieser Website besteht Ihre Herausforderung darin, den kreativsten Code in einem Programm zu schreiben, das eine in Englisch geschriebene Zahl als Eingabe verwendet und in eine Ganzzahlform umwandelt.

Wirklich trockene, lange und gründliche Spezifikationen:

  • Ihr Programm erhält als Eingabe eine Ganzzahl in Kleinbuchstaben Englisch zwischen zeround nine hundred ninety-nine thousand nine hundred ninety-nineeinschließlich.
  • Es darf nur die ganzzahlige Form der Zahl zwischen 0und 999999und nichts anderes (kein Leerzeichen) ausgegeben werden .
  • Die Eingabe enthält NICHT, oder and, wie in one thousand, two hundredoder five hundred and thirty-two.
  • Wenn sowohl die Zehner- als 1auch die Einerstelle ungleich Null sind und die Zehnerstelle größer als ist , werden sie durch ein HYPHEN-MINUS-Zeichen -anstelle eines Leerzeichens getrennt. Das Gleiche gilt für die zehntausenden und tausenden Plätze. Zum Beispiel six hundred fifty-four thousand three hundred twenty-one.
  • Das Programm kann für andere Eingaben undefiniertes Verhalten aufweisen.

Einige Beispiele für ein gut erzogenes Programm:

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

Abraham
quelle
Dies ist weder besonders kreativ, noch entspricht es genau der Spezifikation hier, aber es könnte als Ausgangspunkt nützlich sein: github.com/ghewgill/text2num/blob/master/text2num.py
Greg Hewgill
Ich könnte fast meine Antwort auf diese Frage posten .
Grc
Warum kompliziertes String-Parsen? pastebin.com/WyXevnxb
blutorange
1
Übrigens habe ich einen IOCCC-Eintrag gesehen, der die Antwort auf diese Frage ist.
Snack
2
Was ist mit Dingen wie "vier und zwanzig"?
flauschiger

Antworten:

93

Applescript

Ein albernes, hacky Mash-Up, das einige Cupertino / Mountain View-Leute verärgern könnte, aber ich denke, es ist ein kreatives albernes, hacky 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

Verwendet OSX-Text in Sprache, um die Textnummer auszusprechen, und Google-Audiosuche, um darauf zu warten und sie in eine Ganzzahl umzuwandeln.

Bedarf

  • OSX
  • Google Chrome
  • Spracherkennung in Ihrem Google-Konto aktiviert
  • Lautstärke auf ein vernünftiges Maß erhöht

Die Verzögerungszeiten müssen möglicherweise in Abhängigkeit von Ihrer Chrome-Ladezeit und der Google Lookup-Zeit angepasst werden.

Beispiel Eingabe:

Bildbeschreibung hier eingeben

Beispielausgabe:

Bildbeschreibung hier eingeben

Digitales Trauma
quelle
13
Ich denke , das könnte ein bisschen kreativ sein ...;)
Abraham
5
Lol, das ist cool
Hälfte des
2
Vielleicht zu kreativ.
Cheezey
Nach einer Woche liegt Ihre Antwort mit 74 Stimmen klar an der Spitze. Ich denke, das bedeutet, dass Sie gewinnen! Übrigens, ob ich diesen Code verwende? Es wäre wirklich nützlich für viele reale Projekte, an denen ich gerade arbeite! ;)
Abraham
3
@Abraham Danke! Du machst Witze darüber, dies im Produktionscode zu verwenden, oder?
Digital Trauma
34

Bash, 93 64 55 Zeichen *

In dem fantastischen bsd-gamesPaket, das auf den meisten Linux-Betriebssystemen verfügbar ist, gibt es ein kleines Befehlszeilenspielzeug namens number. Es wandelt Zahlen in englischen Text um, das heißt, es macht genau das Gegenteil von dieser Frage. Es ist wirklich das genaue Gegenteil: Alle Regeln in der Frage werden befolgt number. Es ist fast zu schön, um ein Zufall zu sein.

$ number 42
forty-two.

Natürlich numberbeantwortet die Frage nicht. Wir wollen es umgekehrt. Ich habe eine Weile darüber nachgedacht, versucht, Zeichenfolgen zu analysieren und all das. Dann wurde mir klar, dass ich einfach numberalle 999.999-Nummern anrufen und sehen kann, ob etwas mit der Eingabe übereinstimmt. In diesem Fall hat die erste Zeile, in der sie übereinstimmt, die doppelte Zeilennummer, nach der ich suche ( numbernach jeder Zahl wird eine Punktzeile gedruckt). So einfach ist das. Also, ohne weiteres, hier ist der vollständige Code für meinen Eintrag:

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

Es schließt sogar kurz, so dass das Konvertieren von "zwei" ziemlich schnell ist und noch höhere Zahlen normalerweise in weniger als einer Sekunde auf meiner Box dekodiert werden. Hier ist ein Beispiellauf:

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

Natürlich müssen Sie numberinstalliert haben , damit dies funktioniert.


*: Ja, ich weiß, das ist keine code-golfHerausforderung, aber Kürze ist so ziemlich die einzige erkennbare Qualität meines Beitrags, also ... :)

Wandern Nauta
quelle
8
+1. Für mich ist die numberumgekehrte Verwendung das Kreativste an dieser Antwort. Die Golffreundlichkeit ist auch gut :)
Digital Trauma
1
Das ist eigentlich ziemlich kreativ! Ich mag das!
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());

Magst du welche eval()?

Führen Sie dieses Skript in der Konsole Ihres Browsers aus.

Edit: Danke für das Feedback. Fehler behoben (wieder).

Snack
quelle
wirklich netter Code ^^
Zsitro
2
Wenn Sie so etwas wie "einhundertsechzehn"
eingeben
Dieses Programm schlägt für einige Nummern fehl, die bei der twelveRückkehr beginnen 23.
Abraham
Scheitert an "twenty".
200_success am
seven thousand three hundred thirty fivegib mir10335
Baby
7

Python

Nur um den Ball ins Rollen zu bringen.

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
nur zur Hälfte
quelle
5

Perl + CPAN

Warum das Rad neu erfinden, wenn es schon gemacht wurde?

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

say words2nums $_ while <>;

Dieses Programm liest englische Zeichenfolgen aus der Standardeingabe (oder aus einer oder mehreren als Befehlszeilenargumente angegebenen Dateien), eine pro Zeile, und druckt die entsprechenden Zahlen in der Standardausgabe aus.

Ich habe diesen Code sowohl mit den Beispieleingaben aus der Challenge als auch mit einer umfassenden Testsuite getestet, die aus den Zahlen von 0 bis 999999 besteht, die mit dem Dienstprogramm bsd-games in Text konvertiert wurden number(danke, Wander Nauta!) alle von ihnen. Als Bonus versteht es auch solche Eingaben wie z. B. minus seven(–7), four and twenty(24), four score and seven(87), one gross(144), a baker's dozen(13), eleventy-one(111) und googol(10 100 ).

( Hinweis: Zusätzlich zum Perl-Interpreter selbst benötigt dieses Programm auch das CPAN-Modul Lingua :: EN :: Words2Nums . Hier einige Anweisungen zur Installation von CPAN-Modulen . Benutzer von Debian / Ubuntu Linux können dieses Modul auch über den APT-Paketmanager installieren als liblingua-en-words2nums-perl .)

Ilmari Karonen
quelle
4

Python

Eine allgemeine rekursive Lösung mit Gültigkeitsprüfung. Könnte für den Bereich der erforderlichen Zahlen vereinfacht werden, aber hier ist zu zeigen, denke ich:

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)
CaesiumLifeJacket
quelle
2

VBScript 474

Dies ist eine ziemlich routinemäßige Antwort ... leider so routinemäßig, dass @Snack so ziemlich den gleichen Prozess gepostet hat, aber vor mir.

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)
bequemdrei
quelle
1

Haskell

Ähnlich wie bei anderen rekursiven Lösungen, aber ich habe mir die Zeit genommen, um es sauber zu machen.

Hier ist die vollständige Quelle mit allen Erklärungen: 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
quelle
0

Common Lisp, 94

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

Die Umwandlung von Zahl in Text ist in CL integriert, jedoch nicht umgekehrt. Erstellt eine umgekehrte Zuordnung für die Zahlen und überprüft die Eingabe darauf.

Harry
quelle