如何在PHP中一起添加货币字符串(非标准化输入)?

时间:2020-03-06 14:43:54  来源:igfitidea点击:

我有一个表格,人们可以在其中输入美元价值。

可能的输入:
$ 999,999,999.99
999,999,999.99
999999999
99,999
$ 99,999

用户可以根据自己的意愿输入美元值。我想将输入读取为双精度,以便可以总计它们。

我尝试只是将字符串类型转换为双精度,但这没有用。输出时总计等于50:

$string1 = ",000";
$string2 = "000";
$string3 = "50,000";
$total = (double)$string1 + (double)$string2 + (double)$string3;
echo $total;

解决方案

http://p2p.wrox.com/topic.asp?TOPIC_ID=3099

逐步进行

[编辑]典型...该站点现在似乎已关闭... :(

不是一个班轮,但如果我们去除',则可以:(这是伪代码)

m/^$?(\d+)(?:\.(\d\d))?$/
 $value =  + /100;

那允许$ 9.99,但不允许$ 9. 或者9.9美元,并且没有抱怨放错位置的数千个分隔符(错误或者功能?)

这里存在一个潜在的"局部性"问题,因为我们假设成千上万个以","和美分表示为""。但在欧洲则相反(例如1.000,99)

正则表达式不会将字符串转换为数字。我建议我们使用正则表达式来验证字段(确认它适合我们允许的格式之一),然后仅循环遍历字符串,并丢弃所有非数字和非周期字符。如果我们不关心验证,则可以跳过第一步。第二步仍将其简化为仅数字和句点。

顺便说一句,我们在计算货币值时不能安全地使用浮点数。我们将失去精度,并且很可能最终得出与输入不完全匹配的总数。

更新:我们可以使用以下两个函数来验证输入并将其转换为小数点表示形式。

function validateCurrency($string)
{
    return preg_match('/^$?(\d{1,3})(,\d{3})*(.\d{2})?$/', $string) ||
           preg_match('/^$?\d+(.\d{2})?$/', $string);
}

function makeCurrency($string)
{
    $newstring = "";

    $array = str_split($string);
    foreach($array as $char)
    {
        if (($char >= '0' && $char <= '9') || $char == '.')
        {
            $newstring .= $char;
        }
    }

    return $newstring;
}

第一个功能将与我们可以期望的大多数货币格式匹配" $ 99"," 99,999.00"等。它将不匹配" .00"或者" 99.",也将不匹配大多数欧洲风格的数字(99.999,00 )。在原始字符串上使用它来验证它是有效的货币字符串。

第二个功能将去除数字和小数点以外的所有内容。请注意,它本身仍可能返回无效的字符串(例如,","," .."和" abc"以""," .."和""的形式出现)。验证字符串后,可使用此功能消除多余的逗号;如果要跳过验证,则可单​​独使用此功能。

我建议不要使用浮点数来存储货币值。如果总和变大,则会出现舍入错误。 (好吧,如果它变得很大。)

最好使用具有足够大范围的整数变量,并以美分而不是美元存储输入。

我相信我们可以使用printf来完成此操作,该操作类似于同名的c函数。它的参数可能有些深奥。我们还可以使用php的number_format函数

我们永远都不想将货币值表示为浮点数!

例如,采用以下(看似简单)的代码:

$x = 1.0;
for ($ii=0; $ii < 10; $ii++) {
  $x = $x - .1;
}
var_dump($x);

我们可能会假设它将产生零值,但事实并非如此。由于$ x是一个浮点数,因此实际上它实际上是大于零的一点(1.38777878078E-16),这本身并不是什么大问题,但是这意味着将值与另一个值进行比较是不可行的。 t保证是正确的。例如$ x == 0将产生false。

假设我们获得的是真实货币值,则可以简单地去除不是数字或者小数点的字符:

(pseudocode) 
newnumber = replace(oldnumber, /[^0-9.]/, //)

现在我们可以使用类似

double(newnumber)

但是,这不会处理诸如" 5.6.3"之类的字符串以及其他此类非金钱字符串。这就提出了一个问题:"我们需要处理格式错误的字符串吗?"