正则表达式:将货币金额(从各种格式)转换为有效的浮点数

Regex: Converting currency amounts (from various formats) to a valid float

我正在开发发票解析器,我发现了各种不同的货币格式。与其为每张发票重新实现一个特定的案例,我宁愿有一个适用于所有案例的通用模式,使用正则表达式替换。

示例输入格式

2.578,20
2 354,20
234
234,256.20
234,205
246 548
244'056
26'155.25

12,20
13.33

期望输出

2578.20
2354.20
234
234256.20
234205
246548
244056
26155.25

12.20
13.33

我目前的进度

到目前为止,我已经设法创建了一些几乎可以工作的东西 /^(\d{0,3})?[\.\ ,']?(\d{0,3})([\.,](\d{0,2}))?/ 替换字符串 .

但这会产生输出

2578.20
2354.20
234.
234256.20
234205.
246548.
244056.
26155.25
.
1220.  <---- WRONG
1333.  <---- WRONG

我可以接受在末尾有一个点,因为这适用于 PHP 中的 floatval(),可能也适用于其他语言。但后两种情况无效。我知道它匹配第一个 (\d{0,3}) 而不是末尾的 (\d{0,2}) 模式。但是我不知道如何解决这个问题...

你可以使用 [^\d\n](?!\d\d$)

解释:

[^\d\n] - 否定字符 class - 匹配数字或换行符以外的任何字符

(?!...)` - 负前瞻 - 匹配,如果内部模式在该位置之前不匹配

\d\d$ - 匹配两个数字和字符串结尾

Demo

它会删除任何非数字字符,仅当它们与两位数字一起出现在字符串末尾时才保留,这意味着它们是小数部分:)

用空字符串替换匹配文本。

您可以交替使用 2 个捕获组和 preg_replace_callback

匹配除数字、点或逗号以外的任何字符,或者当右边不是字符串末尾的 2 位数字时匹配点或逗号并用空字符串替换。

否则捕获逗号并将其替换为点。

([^\d.,]|[.,](?!\d{2}$))|(,)

Regex demo | Php demo

例如

$pattern = "~([^\d.,]|[.,](?!\d{2}$))|(,)~m";
$strings = [
    "2.578,20",
    "2 354,20",
    "234",
    "234,256.20",
    "234,205",
    "246 548",
    "244'056",
    "26'155.25",
    "12,20",
    "13.33",
];

foreach ($strings as $string) {
    echo preg_replace_callback($pattern, function ($matches) {
            if (isset($matches[2])) return ".";
            if (isset($matches[1])) return "";
        }, $string) . PHP_EOL;
}

输出

2578.20
2354.20
234
234256.20
234205
246548
244056
26155.25
12.20
13.33