使用RegEx选择数千个分隔符

时间:2019-06-01 14:45:18

标签: php regex localization numbers

我需要更改给定字符串中的小数点分隔符。

哪些RegEx代码只能选择字符串中的千位分隔符?

只有周围有数字时,才需要选择。例如,仅当123,456我需要选择并替换,

我正在将英语数字转换为波斯语(例如:Hello 123变成Hello ۱۲۳)。现在,我也需要用波斯版本替换小数点分隔符。但是我不知道如何用正则表达式选择它。例如Hello 121,534最多成为Hello ۱۲۱/۵۳۴

需要替换的字符是,/

4 个答案:

答案 0 :(得分:4)

使用带有环顾四周的正则表达式。

$new_string = preg_replace('/(?<=\d),(?=\d)/', '/', $string);

DEMO

(?<=\d)表示逗号前必须有一个数字,(?=\d)表示其后必须有一个数字。但是由于这些是环顾四周,因此比赛中不包含它们,因此不会被替换。

答案 1 :(得分:3)

根据您的问题,您面临的主要问题是将英语数字转换为波斯语。

PHP中提供了一个库,该库可以根据语言环境设置格式和解析数字,您可以在 NumberFormatter 类中找到该库,该类利用了 Unicode通用语言环境数据存储库< / em>(CLDR)最终处理世界上所有已知的语言。

因此,在这个小示例中显示了将数字123,456en_UK(或en_US)转换为fa_IR的情况:

$string = '123,456';
$float = (new NumberFormatter('en_UK', NumberFormatter::DECIMAL))->parse($string);
var_dump(
    (new NumberFormatter('fa_IR', NumberFormatter::DECIMAL))->format($float)
);

输出:

string(14) "۱۲۳٬۴۵۶"

play with it on 3v4l.org

现在,这显示(以某种方式)如何转换数字。我对波斯语不是很坚定,所以如果在这里使用错误的语言环境,请原谅。也许还有一些选项可以告诉您要使用哪个字符进行分组,但是在当前示例中,这只是为了说明数字的转换已由现有库负责。您不需要重新发明它,这甚至是一种措辞不当的措辞,这不是一个人可以做的任何事情,或者至少单独这样做会很疯狂。

因此,在澄清了如何转换这些数字之后,仍然存在关于如何在整个文本中进行转换的问题。好吧,为什么不找到所有可能寻找的地点,然后尝试解析匹配项,如果成功(并且只有成功),才能将其转换为其他语言环境。

幸运的是,如果解析失败,NumberFormatter::parse()方法将返回false(如果您对更多详细信息感兴趣,甚至会有更多错误报告),因此这是可行的。

对于正则表达式匹配,它只需要一个与数字匹配(最大匹配获胜)的模式,并且替换可以通过回调完成。在下面的示例中,翻译是冗长的,因此实际的解析和格式设置更加可见:

# some text
$buffer = <<<TEXT
it need to only select , when there is number around it. for example only 
when 123,456 i need to select and replace "," I'm converting English
numbers into Persian (e.g: "Hello 123" becomes "Hello ۱۲۳"). now I need to
replace the Decimal separator with Persian version too. but I don't know how
I can select it with regex. e.g: "Hello 121,534" most become 
"Hello ۱۲۱/۵۳۴" The character that needs to be replaced is , with /
TEXT;    

# prepare formatters
$inFormat = new NumberFormatter('en_UK', NumberFormatter::DECIMAL);
$outFormat = new NumberFormatter('fa_IR', NumberFormatter::DECIMAL);

$bufferWithFarsiNumbers = preg_replace_callback(
    '(\b[1-9]\d{0,2}(?:[ ,.]\d{3})*\b)u',
    function (array $matches) use ($inFormat, $outFormat) {
        [$number] = $matches;

        $result = $inFormat->parse($number);
        if (false === $result) {
            return $number;
        }

        return sprintf("< %s (%.4f) = %s >", $number, $result, $outFormat->format($result));
    },
    $buffer
);

echo $bufferWithFarsiNumbers;

输出:

it need to only select , when there is number around it. for example only 
when < 123,456 (123456.0000) = ۱۲۳٬۴۵۶ > i need to select and replace "," I'm converting English
numbers into Persian (e.g: "Hello < 123 (123.0000) = ۱۲۳ >" becomes "Hello ۱۲۳"). now I need to
replace the Decimal separator with Persian version too. but I don't know how
I can select it with regex. e.g: "Hello < 121,534 (121534.0000) = ۱۲۱٬۵۳۴ >" most become 
"Hello ۱۲۱/۵۳۴" The character that needs to be replaced is , with /

这里的魔力只有两个,它使用带有正则表达式模式的preg_replace_callback来实现数字转换,字符串应该可以满足您的问题需求,但是由于定义了整数部分,因此相对容易细化,并且通过 NumberFormatter 类来过滤误报:

                    pattern for Unicode UTF-8 strings
                                 |
(\b[1-9]\d{0,2}(?:[ ,.]\d{3})*\b)u
  |                 |          |
  |        grouping character  |
  |                            |
word boundary -----------------+

play with it on regex101.com

编辑:

要仅在数千个块中匹配相同的分组字符,可以创建一个命名引用,并重复引用该引用:

(\b[1-9]\d{0,2}(?:(?<grouping_char>[ ,.])\d{3}(?:(?&grouping_char)\d{3})*)?\b)u

get it deciphered and play with it on regex101.com现在变得不那么容易了

要最终确定答案,只需将return子句压缩为return $outFormat->format($result);,而$outFormat NumberFormatter 可能需要更多配置,但可以在闭包中使用,这可以在创建时完成。

play with it on 3v4l.org

我希望这会有所帮助,并打开一个广阔的前景,不要仅仅因为撞墙(而且只有撞墙)而寻找解决方案。仅靠正则表达式通常不是答案。我很确定有正则表达式怪胎可以为您提供非常稳定的单线,但是使用它的上下文将不会非常稳定。但是,没有说只有一个答案。取而代之的是将不同级别的工作(分而治之)放在一起,即使仍然不确定如何对英文数字进行正则表达式格式化,也可以依靠稳定的数字转换。

答案 2 :(得分:0)

您可以编写一个正则表达式来捕获带有千位分隔符的数字,然后将两个数字部分与所需的分隔符进行汇总:

$text = "Hello, world, 121,534" ;
$pattern = "/([0-9]{1,3}),([0-9]{3})/" ;
$new_text = preg_replace($pattern, "$1X$2", $text); // replace comma per 'X', keep other groups intact.

echo $new_text ; // Hello, world, 121X534

答案 3 :(得分:-1)

在PHP中,您可以使用str_replace

$a="Hello 123,456";
echo str_replace(",", "X", $a);

这将返回:Hello 123X456