首页 > 解决方案 > 如何让 NumberFormatter::parse() 只解析实际的数字字符串?

问题描述

我正在尝试解析一些混乱的 CSV 文件中的一些字符串(每个文件大约 100,000 行)。有些列在某些行中被挤压在一起,我正试图让它们不被挤压回到它们正确的列中。需要的部分逻辑是查找给定列中的子字符串是否为数字。

非数字字符串可以是任何东西,包括恰好以数字开头的字符串;数字字符串通常以欧洲方式编写,点用于千位分隔符,逗号用于小数,因此无需经过一堆字符串替换,is_numeric()就不会成功:

\var_dump(is_numeric('3.527,25')); // bool(FALSE)

我认为 - 天真地,它发生了 - 正确的做法是使用NumberFormatter::parse(),但似乎该函数实际上并没有检查作为一个整体给出的字符串是否可以解析为数字字符串 - 相反它只是开始于开头,当它到达数字字符串中不允许的字符时,切断其余部分。

本质上,我正在寻找的东西会产生这个:

$formatter = new \NumberFormatter('de-DE', \NumberFormatter::DECIMAL);
\var_dump($formatter->parse('3.527,25')); // float(3527.25)
\var_dump($formatter->parse('3thisisnotanumber')); // bool(FALSE)

但我能得到的只有这个:

$formatter = new \NumberFormatter('de-DE', \NumberFormatter::DECIMAL);
\var_dump($formatter->parse('3.527,25')); // float(3527.25)
\var_dump($formatter->parse('3thisisnotanumber')); // float(3)

我认为问题可能在于该LENIENT_PARSE属性设置为 true,但将其设置为 false ( $formatter->setAttribute(\NumberFormatter::LENIENT_PARSE, 0)) 无效;只要非数字字符串以数字开头,它们仍然可以很好地解析。

由于有这么多行,并且每行可能有多达十列需要验证,我正在查看每个文件超过一百万个验证 - 因此,我宁愿避免使用preg_match()-based 解决方案,因为百万正则表达式匹配调用将非常昂贵。

是否有某种方法可以告诉NumberFormatter班级您希望它不要宽容,并且仅在整个字符串为数字时才将字符串视为可解析的?

标签: phpnumber-formattingstring-parsing

解决方案


您可以剥离所有分隔符并检查剩下的是否是数值。

function customIsNumeric(string $value): bool
{
    return is_numeric(str_replace(['.', ','], '', $value));
}

现场测试可用在这里


推荐阅读