将以逗号为小数点的数字转换为 float

我有一个价格表,小数点用逗号表示,千位分隔符用点表示。

一些例子:

12,30
116,10
1.563,14

这些都是来自第三方的格式。我想把它们转换成浮点数,然后把它们加在一起。

最好的方法是什么?Number _ format似乎不适合这种格式,而且 Str _ place似乎有点过分,因为我必须在每个数字上多做一次。

有更好的办法吗? 谢谢。

180127 次浏览

If you're using PHP5.3 or above, you can use numfmt_parse to do "a reversed number_format". If you're not, you stuck with replacing the occurrances with preg_replace/str_replace.

from PHP manual:

str_replace — Replace all occurrences of the search string with the replacement string

I would go down that route, and then convert from string to float - floatval

You could use the NumberFormatter class with its parse method.

Using str_replace() to remove the dots is not overkill.

$string_number = '1.512.523,55';
// NOTE: You don't really have to use floatval() here, it's just to prove that it's a legitimate float value.
$number = floatval(str_replace(',', '.', str_replace('.', '', $string_number)));


// At this point, $number is a "natural" float.
print $number;

This is almost certainly the least CPU-intensive way you can do this, and odds are that even if you use some fancy function to do it, that this is what it does under the hood.

Assuming they are in a file or array just do the replace as a batch (i.e. on all at once):

$input = str_replace(array('.', ','), array('', '.'), $input);

and then process the numbers from there taking full advantage of PHP's loosely typed nature.

This function is compatible for numbers with dots or commas as decimals

function floatvalue($val){
$val = str_replace(",",".",$val);
$val = preg_replace('/\.(?=.*\.)/', '', $val);
return floatval($val);
}

This works for all kind of inputs (American or european style)

echo floatvalue('1.325.125,54'); // The output is 1325125.54
echo floatvalue('1,325,125.54'); // The output is 1325125.54
echo floatvalue('59,95');        // The output is 59.95
echo floatvalue('12.000,30');    // The output is 12000.30
echo floatvalue('12,000.30');    // The output is 12000.30

Might look excessive but will convert any given format no mater the locale:

function normalizeDecimal($val, int $precision = 4): string
{
$input = str_replace(' ', '', $val);
$number = str_replace(',', '.', $input);
if (strpos($number, '.')) {
$groups = explode('.', str_replace(',', '.', $number));
$lastGroup = array_pop($groups);
$number = implode('', $groups) . '.' . $lastGroup;
}
return bcadd($number, 0, $precision);
}

Output:

.12           -> 0.1200
123           -> 123.0000
123.91        -> 12345678.9100
123 456 78.91 -> 12345678.9100
123,456,78.91 -> 12345678.9100
123.456.78,91 -> 12345678.9100
123 456 78,91 -> 12345678.9100

For those who want an example of NumberFormatter :

    $test='2,345.67';


//  OOP Version
$numberFormatter=new NumberFormatter('en-AU',NumberFormatter::DECIMAL);
$number=$numberFormatter->parse($test);
print $number;


//  Procedural Version
$numberFormatter=numfmt_create('en_AU',NumberFormatter::DECIMAL);
$number=numfmt_parse($numberFormatter,$test);
print $number;

Of course your locale may very.

Not sure why anyone would opt for the procedural version.

Note that one major difference between NumberFormat and the str_replace type solutions is that NumberFormatter is sensitive to where you put your thousands and decimal characters; using 1,2345.00 won’t work.

You could use filter_var.

$floatNumber = (float) filter_var($string, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);