2

我对基本的 reg-ex 很满意。但是这行代码用于大量进行千次分离超出了我的知识范围,并且在谷歌上搜索了很多也没有满足我的好奇心。你们中的一个可以花点时间向我解释一下下面的代码行吗?

someString.replaceAll("(\\G-?\\d{1,3})(?=(?:\\d{3})++(?!\\d))", "$1,");

我特别不了解正则表达式结构"(?=(?:\d{3})++(?!\d))"

提前非常感谢。

4

3 回答 3

3

"(?=(?:\d{3})++(?!\d))"是一个前瞻断言

它的意思是“只有在后面跟着((我们不需要捕获的三个数字)重复一次或多次(并再次重复一次或多次)(不跟一个数字))时才匹配”。请参阅有关符号的说明。(?:...)这称为非捕获组,意味着您无需在比赛结束后引用该组。

"(\\G-?\\d{1,3})"是实际应该匹配的部分(但前提是满足上述条件)。

编辑:我认为+必须是一个特殊字符,否则它只是一个加号。如果它是一个特殊字符(快速搜索表明它也在 Java 中),那么第二个字符是多余的。

编辑 2:感谢Alan Moore,现在很清楚了。第二个+意思是所有格匹配,所以意思是如果在检查尽可能多的3位组之后,如果没有发现它们后面没有一个非数字,引擎会立即放弃而不是步进一个3-数字组回来。

于 2012-04-07T16:08:47.773 回答
3

这个表达式有一些高级的东西。首先,最简单的:\d{3}正好是三位数。这些是你的成千上万。

then: the++是 + 的变体(表示一个或多个),但具有所有格,这意味着它将吃掉所有的数千个。我不完全确定为什么这是必要的。

?:意味着它是一个非捕获组 - 我认为这只是出于性能原因,可以省略。

?=是一个积极的前瞻 - 我认为这意味着它只检查该组是否存在但不会计入匹配的字符串 - 这意味着它不会被替换。

?!是一个否定的前瞻 - 我不太明白,但我认为这意味着它不能匹配,这反过来意味着在匹配序列的末尾不能有另一个数字。这可以确保第一组得到正确的数字。例如,如果你明白我的意思,10000 只能匹配为 10(000) 而不是 1(000)0。

通过前瞻,如果我理解正确(我没有测试过),实际上只有第一组会被替换,因为它是匹配的。

于 2012-04-07T16:21:36.337 回答
2

对我来说,该正则表达式中最有趣的部分是\G. 我花了一段时间才记住它的用途:防止在分数部分添加逗号(如果有的话)。如果正则表达式很简单:

(-?\d{1,3})(?=(?:\d{3})++(?!\d))

...这个号码:

12345.67890

...最终会是:

12,345.67,890

但是添加\G到开头意味着匹配只能从字符串的开头或上一个匹配结束的位置开始。所以它不匹配345是因为.它跟随它,它不匹配67是因为它必须跳过一些字符串才能这样做。所以它正确返回:

12,345.67890

我知道这不是问题的答案,但我认为值得一提。

于 2012-04-07T19:46:14.007 回答