PHP numaraları kelimeleri dönüştürme

4 Cevap php

I am trying to convert numerical values written as words into integers. For example, "iPhone has two hundred and thirty thousand seven hundred and eighty three apps" would become "iPhone as 230783 apps"

I kodlama başlamadan önce, herhangi bir fonksiyon / kod bu dönüşüm için varsa bilmek istiyorum.

4 Cevap

Kelime numaraları dönüştürme tartışan sayfaları bir sürü vardır. Ters yönde için çok değil. Ben bulabildiğim en iyi Yahoo Ask bazı sözde kod oldu. http://answers.yahoo.com/question/index?qid=20090216103754AAONnDz güzel bir algoritma için bkz:

Belirteçleri (sayılara çevirir kelime) bulma ve dilbilgisi uygulayarak: Peki, genel olarak iki şey yapıyoruz. Kısacası, çok sınırlı bir dil için bir ayrıştırıcı inşa ediyoruz.

Eğer gerekir belirteçleri şunlardır:

POWER: thousand, million, billion
HUNDRED: hundred
TEN: twenty, thirty... ninety
UNIT: one, two, three, ... nine,
SPECIAL: ten, eleven, twelve, ... nineteen

(Anlamsız olduğu gibi "ve" S bırakın. Iki belirteçleri tire kırın. İşte altmış beş "beş", "altmış" olarak işlenmiş gerektiğidir)

Eğer dize tokenized sonra, sağdan sola hareket ettirin.

  1. Bir GÜCÜ veya bütün dize vurmak kadar SAĞ tüm belirteçleri tut.

  2. Bu desenlerin için durma noktasından sonra belirteçleri Ayrıştırma:

    SPECIAL
    TEN
    UNIT
    TEN UNIT
    UNIT HUNDRED
    UNIT HUNDRED SPECIAL
    UNIT HUNDRED TEN
    UNIT HUNDRED UNIT
    UNIT HUNDRED TEN UNIT

    (Bu "on yedi" bu dilbilgisi izin olmadığını varsayar)

    Bu size numarasının son üç rakamını verir.

  3. Eğer bütün dize durdu Eğer yapılır.

  4. Eğer bir güç durdu eğer daha yüksek bir güç ya da tüm dizeyi ulaşana kadar, 1. adımdan tekrar başlayın.

Eski bir soru, ama başka herkes bu genelinde gelecek için ben bugün bu bir çözüm yazmak zorunda kaldım. Aşağıdaki John Kugelman tarafından açıklanan algoritmasına bir belli belirsiz benzer bir yaklaşım, ama sıkı bir dilbilgisi geçerli değildir; gibi bazı tuhaf orderings izin verir, örneğin "100.001 milyon 'hala" bir milyon ve yüz bini "(1,100,000) gibi aynı üretecek. Geçersiz bit (örn. yanlış numaralar) ihmal, böylece tanımsız olarak geçersiz dizeleri çıkışı dikkate alınacaktır.

Joebert cevabı üzerine user132513 yorumuna ardından, test serisi oluşturmak için Armut en Number_Words kullanılır. Aşağıdaki kod 0 ile 5000000 arasındaki numaraları 100% attı sonra 0 ve 10000000 arasında 100.000 numaraları rastgele bir numune üzerinde 100% (o bütün 10 milyar serisi üzerinde çalıştırmak için uzun sürer).

/**
 * 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();
}

Ben de kapsamlı bu test değil, ben çıkışı beklendiği ne gördüm kadar veya daha az sadece üzerinde çalıştı, ancak iş gibi görünüyor, ve gelen ayrıştırır soldan sağa.

<?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";

?>

ARMUT Numbers_Words paketi muhtemelen iyi bir başlangıç: http://pear.php.net/package-info.php?package=Numbers_Words