【问题标题】:Number to Words Conversion (Indian Rupee) decimal String issue in phpphp中的数字到单词转换(印度卢比)十进制字符串问题
【发布时间】:2017-12-29 18:36:39
【问题描述】:

我在PHP中使用Following函数将数字转换为单词。

我预期的结果。

一千五百四十二卢比二十六派斯而已

但是,它的显示

只有一千五百四十二卢比二六派斯

我的功能是:

function displaywords($number){
   $no = round($number);
   $point = round($number - $no, 2) * 100;
   $hundred = null;
   $digits_1 = strlen($no);
   $i = 0;
   $str = array();
   $words = array('0' => '', '1' => 'one', '2' => 'two',
    '3' => 'three', '4' => 'four', '5' => 'five', '6' => 'six',
    '7' => 'seven', '8' => 'eight', '9' => 'nine',
    '10' => 'ten', '11' => 'eleven', '12' => 'twelve',
    '13' => 'thirteen', '14' => 'fourteen',
    '15' => 'fifteen', '16' => 'sixteen', '17' => 'seventeen',
    '18' => 'eighteen', '19' =>'nineteen', '20' => 'twenty',
    '30' => 'thirty', '40' => 'forty', '50' => 'fifty',
    '60' => 'sixty', '70' => 'seventy',
    '80' => 'eighty', '90' => 'ninety');
   $digits = array('', 'hundred', 'thousand', 'lakh', 'crore');
   while ($i < $digits_1) {
     $divider = ($i == 2) ? 10 : 100;
     $number = floor($no % $divider);
     $no = floor($no / $divider);
     $i += ($divider == 10) ? 1 : 2;


     if ($number) {
        $plural = (($counter = count($str)) && $number > 9) ? 's' : null;
        $hundred = ($counter == 1 && $str[0]) ? ' and ' : null;
        $str [] = ($number < 21) ? $words[$number] .
            " " . $digits[$counter] . $plural . " " . $hundred
            :
            $words[floor($number / 10) * 10]
            . " " . $words[$number % 10] . " "
            . $digits[$counter] . $plural . " " . $hundred;
     } else $str[] = null;
  }
  $str = array_reverse($str);
  $result = implode('', $str);


  $points = ($point) ?
    "" . $words[$point / 10] . " " . 
          $words[$point = $point % 10] : ''; 

  if($points != ''){        
  echo $result . "Rupees  " . $points . " Paise Only";
} else {

    echo $result . "Rupees Only";
}

}

$ins=1542.26;

echo displaywords($ins);

【问题讨论】:

  • 你传入的值是多少?
  • @KevinKyaw $ins=1542.26;

标签: php laravel function numbers


【解决方案1】:

我将代码稍微改写为更高效的代码。 (我认为)。
它使用更少的变量、没有内爆、没有数组函数、更少的 if 和更少的计算。

它将. 处的数字分解并使其成为一个数组并在相同的代码($val)中单独处理它们。
然后它获取字符串的每个数字并将其 str_pads 到它的“主要数字”(不知道更好的说法)。
所以 1526,它查看 1,并使用 str_pad 使其变为 1000。
如果它高于 90,则同时使用 $words 和 $digits。

此代码还将处理 0.5010 等数字。

function displaywords($number){
    $words = array('0' => '', '1' => 'one', '2' => 'two',
    '3' => 'three', '4' => 'four', '5' => 'five', '6' => 'six',
    '7' => 'seven', '8' => 'eight', '9' => 'nine',
    '10' => 'ten', '11' => 'eleven', '12' => 'twelve',
    '13' => 'thirteen', '14' => 'fourteen',
    '15' => 'fifteen', '16' => 'sixteen', '17' => 'seventeen',
    '18' => 'eighteen', '19' =>'nineteen', '20' => 'twenty',
    '30' => 'thirty', '40' => 'forty', '50' => 'fifty',
    '60' => 'sixty', '70' => 'seventy',
    '80' => 'eighty', '90' => 'ninety');
    $digits = array('', '', 'hundred', 'thousand', 'lakh', 'crore');

    $number = explode(".", $number);
    $result = array("","");
    $j =0;
    foreach($number as $val){
        // loop each part of number, right and left of dot
        for($i=0;$i<strlen($val);$i++){
            // look at each part of the number separately  [1] [5] [4] [2]  and  [5] [8]

            $numberpart = str_pad($val[$i], strlen($val)-$i, "0", STR_PAD_RIGHT); // make 1 => 1000, 5 => 500, 4 => 40 etc.
            if($numberpart <= 20){ // if it's below 20 the number should be one word
                $numberpart = 1*substr($val, $i,2); // use two digits as the word
                $i++; // increment i since we used two digits
                $result[$j] .= $words[$numberpart] ." ";
            }else{
                //echo $numberpart . "<br>\n"; //debug
                if($numberpart > 90){  // more than 90 and it needs a $digit.
                    $result[$j] .= $words[$val[$i]] . " " . $digits[strlen($numberpart)-1] . " "; 
                }else if($numberpart != 0){ // don't print zero
                    $result[$j] .= $words[str_pad($val[$i], strlen($val)-$i, "0", STR_PAD_RIGHT)] ." ";
                }
            }
        }
        $j++;
    }
    if(trim($result[0]) != "") echo $result[0] . "Rupees ";
    if($result[1] != "") echo $result[1] . "Paise";
    echo " Only";
}

$ins=1516.16;

echo displaywords($ins);

https://3v4l.org/rFvbJ

在代码中添加了一些 cmets。
注意到它在较大的数字上给出了错误的输出,已更正。

【讨论】:

  • 当我给 $ins=1542.58;.它的显示只有一千五百四十三卢比佩斯...五十八不见了@Andreas
  • @Karthik 现在看看。
  • 回显显示字(1542.16);其显示“仅一千五百四十二卢比十八派斯”
  • 不,不是! 3v4l.org/58foa 它输出正确 one thousand five hundred forty two Rupees ten six Paise Only
  • 不是十个六...十六个正确
【解决方案2】:
function displaywords($number){
   $no = (int)floor($number);
   $point = (int)round(($number - $no) * 100);
   $hundred = null;
   $digits_1 = strlen($no);
   $i = 0;
   $str = array();
   $words = array('0' => '', '1' => 'one', '2' => 'two',
    '3' => 'three', '4' => 'four', '5' => 'five', '6' => 'six',
    '7' => 'seven', '8' => 'eight', '9' => 'nine',
    '10' => 'ten', '11' => 'eleven', '12' => 'twelve',
    '13' => 'thirteen', '14' => 'fourteen',
    '15' => 'fifteen', '16' => 'sixteen', '17' => 'seventeen',
    '18' => 'eighteen', '19' =>'nineteen', '20' => 'twenty',
    '30' => 'thirty', '40' => 'forty', '50' => 'fifty',
    '60' => 'sixty', '70' => 'seventy',
    '80' => 'eighty', '90' => 'ninety');
   $digits = array('', 'hundred', 'thousand', 'lakh', 'crore');
   while ($i < $digits_1) {
     $divider = ($i == 2) ? 10 : 100;
     $number = floor($no % $divider);
     $no = floor($no / $divider);
     $i += ($divider == 10) ? 1 : 2;


     if ($number) {
        $plural = (($counter = count($str)) && $number > 9) ? 's' : null;
        $hundred = ($counter == 1 && $str[0]) ? ' and ' : null;
        $str [] = ($number < 21) ? $words[$number] .
            " " . $digits[$counter] . $plural . " " . $hundred
            :
            $words[floor($number / 10) * 10]
            . " " . $words[$number % 10] . " "
            . $digits[$counter] . $plural . " " . $hundred;
     } else $str[] = null;
  }
  $str = array_reverse($str);
  $result = implode('', $str);


  if ($point > 20) {
    $points = ($point) ?
      "" . $words[floor($point / 10) * 10] . " " . 
          $words[$point = $point % 10] : ''; 
  } else {
      $points = $words[$point];
  }
  if($points != ''){        
      echo $result . "Rupees  " . $points . " Paise Only";
  } else {

      echo $result . "Rupees Only";
  }

}


echo displaywords(1542.26);
echo "\n";
echo displaywords(1542.58);

【讨论】:

  • 或许有什么解释?
  • 此代码不能很好地处理 1 以下的数字。例如:3v4l.org/LQKar 并使用偶数(10、20、30 等)的 nubers 创建额外的间距。 3v4l.org/lKFTb
  • @mokamoto12 echo displaywords(1542.16);其显示“仅 1542 卢比 tensix Paise”
  • @Karthik 抱歉回复晚了。也许修复它,displaywords(1542.16);只返回一千五百四十二卢比十六派斯
  • 对于小于 1 的数字仍然会输出额外的空格和错误的字符串。
【解决方案3】:
<?php
set_error_handler('exceptions_error_handler');

function exceptions_error_handler($severity, $message, $filename, $lineno) {
  if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}

function convert_number_to_words($number) {

$hyphen      = '-';
$conjunction = ' and ';
$separator   = ', ';
$negative    = 'negative ';
$decimal     = ' point ';
$dictionary  = array(
    0                   => 'zero',
    1                   => 'one',
    2                   => 'two',
    3                   => 'three',
    4                   => 'four',
    5                   => 'five',
    6                   => 'six',
    7                   => 'seven',
    8                   => 'eight',
    9                   => 'nine',
    10                  => 'ten',
    11                  => 'eleven',
    12                  => 'twelve',
    13                  => 'thirteen',
    14                  => 'fourteen',
    15                  => 'fifteen',
    16                  => 'sixteen',
    17                  => 'seventeen',
    18                  => 'eighteen',
    19                  => 'nineteen',
    20                  => 'twenty',
    30                  => 'thirty',
    40                  => 'fourty',
    50                  => 'fifty',
    60                  => 'sixty',
    70                  => 'seventy',
    80                  => 'eighty',
    90                  => 'ninety',
    100                 => 'hundred',
    1000                => 'thousand',
    100000             => 'lakh',
    10000000          => 'crore'
);

if (!is_numeric($number)) {
    return false;
}

if (($number >= 0 && (int) $number < 0) || (int) $number < 0 - PHP_INT_MAX) {
    // overflow
    trigger_error(
        'convert_number_to_words only accepts numbers between -' . PHP_INT_MAX . ' and ' . PHP_INT_MAX,
        E_USER_WARNING
    );
    return false;
}

if ($number < 0) {
    return $negative . convert_number_to_words(abs($number));
}

$string = $fraction = null;

if (strpos($number, '.') !== false) {
    list($number, $fraction) = explode('.', $number);
}

switch (true) {
    case $number < 21:
        $string = $dictionary[$number];
        break;
    case $number < 100:
        $tens   = ((int) ($number / 10)) * 10;
        $units  = $number % 10;
        $string = $dictionary[$tens];
        if ($units) {
            $string .= $hyphen . $dictionary[$units];
        }
        break;
    case $number < 1000:
        $hundreds  = $number / 100;
        $remainder = $number % 100;
        $string = $dictionary[$hundreds] . ' ' . $dictionary[100];
        if ($remainder) {
            $string .= $conjunction . convert_number_to_words($remainder);
        }
        break;
    case $number < 100000:
        $thousands   = ((int) ($number / 1000));
        $remainder = $number % 1000;

        $thousands = convert_number_to_words($thousands);

        $string .= $thousands . ' ' . $dictionary[1000];
        if ($remainder) {
            $string .= $separator . convert_number_to_words($remainder);
        }
        break;
    case $number < 10000000:
        $lakhs   = ((int) ($number / 100000));
        $remainder = $number % 100000;

        $lakhs = convert_number_to_words($lakhs);

        $string = $lakhs . ' ' . $dictionary[100000];
        if ($remainder) {
            $string .= $separator . convert_number_to_words($remainder);
        }
        break;
    case $number < 1000000000:
        $crores   = ((int) ($number / 10000000));
        $remainder = $number % 10000000;

        $crores = convert_number_to_words($crores);

        $string = $crores . ' ' . $dictionary[10000000];
        if ($remainder) {
            $string .= $separator . convert_number_to_words($remainder);
        }
        break;
    default:
        $baseUnit = pow(1000, floor(log($number, 1000)));
        $numBaseUnits = (int) ($number / $baseUnit);
        $remainder = $number % $baseUnit;
        try
        {
        $string = convert_number_to_words($numBaseUnits) . ' ' . $dictionary[$baseUnit];
        }catch(Exception $e)
        {
            return "Value too large";
        }
        if ($remainder) {
            $string .= $remainder < 100 ? $conjunction : $separator;
            $string .= convert_number_to_words($remainder);
        }
        break;
}

if (null !== $fraction && is_numeric($fraction)) {
    $string .= $decimal;
    $words = array();
    foreach (str_split((string) $fraction) as $number) {
        $words[] = $dictionary[$number];
    }
    $string .= implode(' ', $words);
}

return $string;
}

echo convert_number_to_words(100000000);
?>

【讨论】:

  • 最佳答案!
猜你喜欢
  • 2023-02-08
  • 2015-05-22
  • 2020-11-07
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
相关资源
最近更新 更多