Java 这个正则表达式行超出了我的理解;(?=(?:\d{3})和(?!\d))”;

Java 这个正则表达式行超出了我的理解;(?=(?:\d{3})和(?!\d))”;,java,regex,Java,Regex,我对基本的reg-ex很满意。但是这行代码用来将千个数字分开,这超出了我的知识范围,谷歌搜索也不能满足我的好奇心。请你们中的一位花一分钟向我解释一下下面的代码行好吗 someString.replaceAll("(\\G-?\\d{1,3})(?=(?:\\d{3})++(?!\\d))", "$1,"); 我特别不理解regex结构“(?=(?:\d{3})++(?!\d))” 非常感谢。“(?=(?:\d{3})++(?!\d))”是一个很好的例子 它的意思是“仅当后跟((我们不需要捕获的

我对基本的reg-ex很满意。但是这行代码用来将千个数字分开,这超出了我的知识范围,谷歌搜索也不能满足我的好奇心。请你们中的一位花一分钟向我解释一下下面的代码行好吗

someString.replaceAll("(\\G-?\\d{1,3})(?=(?:\\d{3})++(?!\\d))", "$1,");
我特别不理解regex结构
“(?=(?:\d{3})++(?!\d))”

非常感谢。

“(?=(?:\d{3})++(?!\d))”
是一个很好的例子

它的意思是“仅当后跟((我们不需要捕获的三个数字)重复一次或多次(并且再次重复一次或多次)(不后跟数字))时才匹配”。有关
(?:…)
符号,请参见此。它被称为非捕获组,意味着比赛后你不需要引用该组

“(\\G-?\\d{1,3})”
是实际匹配的部分(但仅当满足上述条件时)

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


编辑2:多亏了,现在已经清楚了。第二个
+
表示所有格匹配,因此这意味着如果在检查尽可能多的3位数字组后,它不会发现后面没有非数字组,引擎将立即放弃,而不是后退一个3位数字组。

此表达式包含一些高级内容。 首先,最简单的:
\d{3}
表示正好三位数字。这些是你的几千

然后:
++
是+(意思是一个或多个)的一个变体,但是占有,意思是它会吃掉所有的几千个。我不完全确定为什么这是必要的

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

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

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


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

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

(?\d{1,3})(?=(?:\d{3})++(?!\d))
…此号码:

12345.67890
…最终将成为:

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

12345.67890

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

不,第二个
+
不是多余的;它产生了第一个
+
。使用“++”和“+”进行实验不会对结果产生任何影响,无论我在整数后面放了什么(在java中)。所以我想这实际上只是一个性能问题。@dotwin对于当前情况来说,这是正确的,因为如果它后退3位,那么匹配候选字符后面的下一个字符显然是一位数字,因此它将再次失败。这就是添加
++
的原因:为了防止浪费时间。所有格
++
实际上是不必要的。它使正则表达式的效率稍微提高了一点(正如@Lev所观察到的),但我怀疑您是否会注意到其中的差异。正确的是
(?!\d)
。正则表达式将匹配多组数字;例如,在
12345678
中,它将首先匹配
12
,然后匹配
345