Konvertieren von Wörtern in Zahlen in PHP

Lesezeit: 8 Minuten

Ich versuche, als Wörter geschriebene numerische Werte in ganze Zahlen umzuwandeln. Zum Beispiel würde „iPhone hat zweihundertdreißigtausendsiebenhundertdreiundachtzig Apps“ zu „iPhone als 230783 Apps“ werden.

Bevor ich mit dem Codieren beginne, würde ich gerne wissen, ob für diese Konvertierung eine Funktion / ein Code vorhanden ist.

Konvertieren von Wortern in Zahlen in PHP
John Kugelmann

Es gibt viele Seiten, die die Umwandlung von Zahlen in Wörter diskutieren. Nicht so viele für die umgekehrte Richtung. Das Beste, was ich finden konnte, war irgendein Pseudo-Code auf Ask Yahoo. Sehen http://answers.yahoo.com/question/index?qid=20090216103754AAONnDz für einen schönen Algorithmus:

Nun, insgesamt tun Sie zwei Dinge: Token (Wörter, die sich in Zahlen übersetzen lassen) finden und Grammatik anwenden. Kurz gesagt, Sie bauen einen Parser für eine sehr begrenzte Sprache.

Die Tokens, die Sie benötigen, sind:

MACHT: Tausend, Millionen, Milliarden
HUNDERT: hundert
ZEHN: zwanzig, dreißig … neunzig
EINHEIT: eins, zwei, drei, … neun,
SPECIAL: zehn, elf, zwölf, … neunzehn

(Lassen Sie alle “und”s weg, da sie bedeutungslos sind. Trennen Sie Bindestriche in zwei Token. Das ist fünfundsechzig sollte als “sechzig” “fünf” verarbeitet werden.)

Sobald Sie Ihre Zeichenfolge tokenisiert haben, bewegen Sie sich von RECHTS NACH LINKS.

  1. Nimm alle Token von RECHTS, bis du eine POWER oder die ganze Saite triffst.

  2. Analysieren Sie die Token nach dem Stopppunkt für diese Muster:

    BESONDERE
    ZEHN
    EINHEIT
    ZEHN EINHEIT
    EINHEIT HUNDERT
    EINHEIT HUNDERT SPEZIELL
    EINHEIT HUNDERT ZEHN
    EINHEIT HUNDERT EINHEIT
    EINHEIT HUNDERT ZEHN EINHEIT

    (Dies setzt voraus, dass “siebzehnhundert” in dieser Grammatik nicht erlaubt ist.)

    Dadurch erhalten Sie die letzten drei Ziffern Ihrer Nummer.

  3. Wenn Sie an der ganzen Saite angehalten haben, sind Sie fertig.

  4. Wenn Sie bei einer Potenz aufgehört haben, beginnen Sie wieder bei Schritt 1, bis Sie eine höhere POWER oder die ganze Saite erreicht haben.

  • Danke Johannes! Dieser Algo ist genau das, wonach ich gesucht habe. Ich habe versucht, es von links nach rechts zu analysieren, aber das sieht besser aus. Schätze deine Hilfe!

    – Benutzer132513

    3. Juli 2009 um 5:31 Uhr

  • Ich habe unten eine Antwort hinzugefügt, die einen vage ähnlichen Algorithmus implementiert.

    – El Yobo

    27. Juni 2012 um 5:13 Uhr

1646312647 873 Konvertieren von Wortern in Zahlen in PHP
El Yobo

Alte Frage, aber für alle anderen, die darauf stoßen, musste ich heute eine Lösung dafür schreiben. Das Folgende verfolgt einen vage ähnlichen Ansatz wie der von John Kugelman beschriebene Algorithmus, wendet jedoch keine so strenge Grammatik an; als solches wird es einige seltsame Reihenfolgen erlauben, zB “Hunderttausendundeine Million” ergibt immer noch dasselbe wie “Eine Million und Hunderttausend” (1.100.000). Ungültige Bits (z. B. falsch geschriebene Zahlen) werden ignoriert, sodass die Ausgabe ungültiger Zeichenketten als undefiniert betrachtet wird.

Nach dem Kommentar von user132513 zu Joeberts Antwort habe ich Pear’s Number_Words verwendet, um Testreihen zu generieren. Der folgende Code erzielte 100 % bei Zahlen zwischen 0 und 5.000.000 und dann 100 % bei einer Zufallsstichprobe von 100.000 Zahlen zwischen 0 und 10.000.000 (es dauert zu lange, um die gesamten 10-Milliarden-Reihen zu durchlaufen).

/**
 * Convert a string such as "one hundred thousand" to 100000.00.
 *
 * @param string $data The numeric string.
 *
 * @return float or false on error
 */
function wordsToNumber($data) {
    // Replace all number words with an equivalent numeric value
    $data = strtr(
        $data,
        array(
            'zero'      => '0',
            'a'         => '1',
            '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',
            'fourty'    => '40', // common misspelling
            'fifty'     => '50',
            'sixty'     => '60',
            'seventy'   => '70',
            'eighty'    => '80',
            'ninety'    => '90',
            'hundred'   => '100',
            'thousand'  => '1000',
            'million'   => '1000000',
            'billion'   => '1000000000',
            'and'       => '',
        )
    );

    // Coerce all tokens to numbers
    $parts = array_map(
        function ($val) {
            return floatval($val);
        },
        preg_split('/[\s-]+/', $data)
    );

    $stack = new SplStack; // Current work stack
    $sum   = 0; // Running total
    $last  = null;

    foreach ($parts as $part) {
        if (!$stack->isEmpty()) {
            // We're part way through a phrase
            if ($stack->top() > $part) {
                // Decreasing step, e.g. from hundreds to ones
                if ($last >= 1000) {
                    // If we drop from more than 1000 then we've finished the phrase
                    $sum += $stack->pop();
                    // This is the first element of a new phrase
                    $stack->push($part);
                } else {
                    // Drop down from less than 1000, just addition
                    // e.g. "seventy one" -> "70 1" -> "70 + 1"
                    $stack->push($stack->pop() + $part);
                }
            } else {
                // Increasing step, e.g ones to hundreds
                $stack->push($stack->pop() * $part);
            }
        } else {
            // This is the first element of a new phrase
            $stack->push($part);
        }

        // Store the last processed part
        $last = $part;
    }

    return $sum + $stack->pop();
}

  • Ich fand das eine sehr robuste und prägnante Lösung. Gut gemacht! Meine einzige Änderung war das Hinzufügen 'lakh' => '100000' und 'crore' => '10000000' wie von user132513 in joeberts Antwort erwähnt.

    – Chior

    13. Februar 2013 um 12:20 Uhr

  • Ein Anwendungsfall, bei dem dies nicht funktioniert, ist z $data= 'five or ten'. Dies gibt 50 zurück. Die obige Antwort funktioniert gut für das OP. Allerdings muss man davon ausgehen, dass der String “korrekt” formatiert ist. In meinem Fall habe ich versucht, die Zahl aus einer ungeprüften Zeichenfolge zu entfernen, ohne zu kontrollieren (oder zu wissen), was die Zeichenfolge sein könnte. Benutzer fügen manchmal einige ziemlich seltsame Antworten in Formulare ein!

    – Sablefoste

    18. Dezember 2014 um 15:52 Uhr

  • “Ungültige Bits (z. B. falsch geschriebene Zahlen) werden ignoriert, daher betrachten sie die Ausgabe ungültiger Zeichenketten als undefiniert”; Leider soll dies nur eine Zeichenfolge konvertieren, die eine einzelne Zahl enthält. Sie könnten versuchen, Ihre Zeichenfolge mit dem in Fragmente aufzuteilen $data Liste oben auf (da dies die einzigen Teilzeichenfolgen sind, die uns interessieren) und führen Sie sie dann für jedes Fragment aus und kombinieren Sie dann die Ergebnisse mit den getrennten Wörtern.

    – El Yobo

    18. Dezember 2014 um 21:14 Uhr

  • @ElYobo Es funktioniert gut, außer dass, wenn die $daten Wert ist Zehn anstatt zehn dann kehrt es zurück 0 anstatt 10 . Bitte helfen Sie dabei mit Groß- und Kleinschreibung sich paaren.

    – Raja Gopal

    25. September 2016 um 5:32 Uhr


  • Ich würde empfehlen, dies als erste Zeile zu verwenden: $data = strtolower(trim($data));. Dies spricht den von @RajaGopal angesprochenen Punkt an

    – sean.boyer

    15. März 2017 um 15:00 Uhr

Ich habe das nicht zu ausführlich getestet, ich habe mehr oder weniger nur daran gearbeitet, bis ich sah, was ich in der Ausgabe erwartet hatte, aber es scheint zu funktionieren und von links nach rechts zu analysieren.

<?php

$str="twelve billion people know iPhone has two hundred and thirty thousand, seven hundred and eighty-three apps as well as over one million units sold";

function strlen_sort($a, $b)
{
    if(strlen($a) > strlen($b))
    {
        return -1;
    }
    else if(strlen($a) < strlen($b))
    {
        return 1;
    }
    return 0;
}

$keys = array(
    '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', 'seventy' => '70', 'eighty' => '80', 'ninety' => '90',
    'hundred' => '100', 'thousand' => '1000', 'million' => '1000000', 'billion' => '1000000000'
);


preg_match_all('#((?:^|and|,| |-)*(\b' . implode('\b|\b', array_keys($keys)) . '\b))+#i', $str, $tokens);
//print_r($tokens); exit;
$tokens = $tokens[0];
usort($tokens, 'strlen_sort');

foreach($tokens as $token)
{
    $token = trim(strtolower($token));
    preg_match_all('#(?:(?:and|,| |-)*\b' . implode('\b|\b', array_keys($keys)) . '\b)+#', $token, $words);
    $words = $words[0];
    //print_r($words);
    $num = '0'; $total = 0;
    foreach($words as $word)
    {
        $word = trim($word);
        $val = $keys[$word];
        //echo "$val\n";
        if(bccomp($val, 100) == -1)
        {
            $num = bcadd($num, $val);
            continue;
        }
        else if(bccomp($val, 100) == 0)
        {
            $num = bcmul($num, $val);
            continue;
        }
        $num = bcmul($num, $val);
        $total = bcadd($total, $num);
        $num = '0';
    }
    $total = bcadd($total, $num);
    echo "$total:$token\n";
    $str = preg_replace("#\b$token\b#i", number_format($total), $str);
}
echo "\n$str\n";

?>

  • Ein Fehler wurde gefunden, es fehlen gängige Mischungen aus Zahlen und Wörtern wie “2 Millionen”.

    – joebert

    3. Juli 2009 um 6:21 Uhr

  • Es wird auch mit bestimmten Formulierungen für Daten durcheinander kommen. “Ich wurde 1981 geboren”

    – joebert

    3. Juli 2009 um 6:27 Uhr

  • Vielen Dank Joebert für den Code! Ich werde versuchen, es zu verbessern. Ich habe einen Testsatz von 10000 zufälligen Zahlenwörtern (unter Verwendung von Numbers_Words) eingerichtet und derzeit beträgt die Genauigkeit der Dekodierung von Wörtern in Zahlen 75%. Richtig: Fünfundvierzigtausendfünfhundertvierundfünfzig wird zu 45554. Falsch: Einundfünfzigtausendfünfhundertsechsundachtzig wird zu 586

    – Benutzer132513

    9. Juli 2009 um 1:17 Uhr

  • Habe gerade das Problem erkannt. Es passiert etwas Komisches beim Zugriff auf den ersten Schlüssel, dh „Eins“. Setzen Sie stattdessen „Billiarde“ => „1000000000000000“ vor „Eins“ und es funktioniert mit 100%iger Genauigkeit.

    – Benutzer132513

    10. Juli 2009 um 1:28 Uhr

  • Fügen Sie außerdem ‘lakh’ => ‘100000’ und ‘crore’ => ‘10000000’ in $keys ein. Sie sind häufigere Begriffe als Millionen in südasiatischen Ländern

    – Benutzer132513

    10. Juli 2009 um 1:30 Uhr

Konvertieren von Wortern in Zahlen in PHP
der Fisch

El Yobos Antwort wurde etwas aktualisiert, jetzt kann man die wordsToNumber-Funktion über (fast) jede Zeichenfolge ausführen, die Ziffern enthält.

https://github.com/thefish/words-to-number-converter

converter.php – Konverter selbst

test.php – Test mit verschiedenen Strings

UPD 22.10.2020: Die Antwort wird zu groß, um sie zu warten. Code nach github verschoben.

Der einfachste Weg, den ich gefunden habe, ist die Verwendung numfmt_parse:

$fmt = numfmt_create('en_US', NumberFormatter::SPELLOUT);
echo numfmt_parse($fmt, 'one million two hundred thirty-four thousand five hundred sixty-seven');

(Quelle; Dorians Beitrag unter https://stackoverflow.com/a/31588055/11827985):

1646312649 204 Konvertieren von Wortern in Zahlen in PHP
Jani Hartikainen

Die Birne Numbers_Words Paket ist wahrscheinlich ein guter Anfang: http://pear.php.net/package-info.php?package=Numbers_Words

923660cookie-checkKonvertieren von Wörtern in Zahlen in PHP

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy