对于在线计算器,用户可以输入能量来计算相应的费用,我需要PHP脚本来接受各种用户输入。 “200万和1/4焦耳”的值可以输入为:
2000000.25(默认表示法)
2,000,000.25(有千位分隔符)
2000000,25(逗号为小数点)
2.000.000,25(逗号为小数点,千位分隔符)
2'000'000.25(替代格式)
2 000 000,25(法文符号)
如何让脚本知道这些差异?
我的第一次尝试是使用默认的str_replace替换字符,但句点(。)可以是十进制或千位分隔符。我尝试使用sscanf,但我怎样才能确保它正确读取数字?
大多数用户只会在小数点后面提供两位数字,但有什么方法可以区分1.234(1点234,句号为十进制分隔符)和1.234(一千二百三十四,句号为千位分隔符) ?
答案 0 :(得分:1)
无法知道1.234
的含义。
,
或.
替换为该分隔符,
和.
答案 1 :(得分:0)
由于我无法通过一些内置的PHP函数找到一个简单的解决方案,我写了两个函数来(1)检查输入的字符串是否可以是一个数字;(2)如果它是好的 - 根据使用的分离器形成。
我将可能的分隔符限制为句点(.
),逗号(,
),空格()和撇号(
'
)作为千位分隔符。小数点可能只是前两个选项之一。可以编辑这两组分隔符以允许更多分隔符或限制它们。
我实际做的是使用几个简单的preg_match_all
调用来查找所有数字列和所有分隔符。
完整的代码如下所示,应该是自我解释的,因为我在抛出false
时添加了一些注释。我敢肯定,这可以通过某种方式进行简化,但它现在可以正常工作并过滤许多错误,同时允许甚至一些奇怪的组合,例如2 000 000.25
或2'000'000,25
。
function check_number($number) {
if ((int) substr($number,0,1) == 0) {
return false; // not starting with a digit greater than 0
}
if ((string) substr($number,-1) != "0" && (int) substr($number,-1) == 0) {
return false; // not ending with a digit
}
preg_match_all('/([^0-9]{2,})/', $number, $sep, PREG_PATTERN_ORDER);
if (isset($sep[0][0])) {
return false; // more than one consecutive non-digit character
}
preg_match_all('/([^0-9]{1})/', $number, $sep, PREG_PATTERN_ORDER);
if (count($sep[0]) > 2 && count(array_unique($sep[0])) > 2) {
return false; // more than 2 different separators
}
elseif (count($sep[0]) > 2) {
$last_sep = array_pop($sep[0]);
if (!in_array($last_sep,array(".",","))) {
return false; // separator not allowed as last one
}
$sep_unique = array_unique($sep[0]);
if (count($sep_unique) > 1) {
return false; // not all separators (except last one) are identical
}
elseif (!in_array($sep_unique[0],array("'",".",","," "))) {
return false; // separator not allowed
}
}
return true;
}
function convert_number($number) {
preg_match_all('/([0-9]+)/', $number, $num, PREG_PATTERN_ORDER);
preg_match_all('/([^0-9]{1})/', $number, $sep, PREG_PATTERN_ORDER);
if (count($sep[0]) == 0) {
// no separator, integer
return (int) $num[0][0];
}
elseif (count($sep[0]) == 1) {
// one separator, look for last number column
if (strlen($num[0][1]) == 3) {
if (strlen($num[0][0]) <= 3) {
// treat as thousands seperator
return (int) ($num[0][0] * 1000 + $num[0][1]);
}
elseif (strlen($num[0][0]) > 3) {
// must be decimal point
return (float) ($num[0][0] + $num[0][1] / 1000);
}
}
else {
// must be decimal point
return (float) ($num[0][0] + $num[0][1] / pow(10,strlen($num[0][1])));
}
}
else {
// multiple separators, check first an last
if ($sep[0][0] == end($sep[0])) {
// same character, only thousands separators, check well-formed nums
$value = 0;
foreach($num[0] AS $p => $n) {
if ($p == 0 && strlen($n) > 3) {
return -1; // malformed number, incorrect thousands grouping
}
elseif ($p > 0 && strlen($n) != 3) {
return -1; // malformed number, incorrect thousands grouping
}
$value += $n * pow(10, 3 * (count($num[0]) - 1 - $p));
}
return (int) $value;
}
else {
// mixed characters, thousands separators and decimal point
$decimal_part = array_pop($num[0]);
$value = 0;
foreach($num[0] AS $p => $n) {
if ($p == 0 && strlen($n) > 3) {
return -1; // malformed number, incorrect thousands grouping
}
elseif ($p > 0 && strlen($n) != 3) {
return -1; // malformed number, incorrect thousands grouping
}
$value += $n * pow(10, 3 * (count($num[0]) - 1 - $p));
}
return (float) ($value + $decimal_part / pow(10,strlen($decimal_part)));
}
}
}
我知道这组函数有一个缺陷:1.234
或1,234
将始终被视为整数1234
,因为该函数假定分隔符必须为千位如果单个分隔符前面的数字少于4位,则为分隔符。