首页 > 解决方案 > \G 如何在 .split 中工作?

问题描述

我喜欢在 Java 中进行代码打高尔夫球(尽管 Java 过于冗长而无法竞争),这是用尽可能少的字节完成某个挑战。在我的一个答案中,我有以下代码:

for(var p:"A4;B8;CU;EM;EW;E3;G6;G9;I1;L7;NZ;O0;R2;S5".split(";"))

在我们将其转换为带有.split. 有人建议我可以用它来代替它以节省 4 个字节:

for(var p:"A4B8CUEMEWE3G6G9I1L7NZO0R2S5".split("(?<=\\G..)"))

功能还是一样的。它遍历 2-char 字符串。

但是,我们都不是 100% 确定这是如何工作的,因此提出了这个问题。


我知道的:

我知道.split("(?<= ... )")用于拆分,但保留尾随分隔符。
还有一种方法可以将前导定界符或定界符保留为单独的项目:

"a;b;c;d".split("(?<=;)")            // Results in ["a;", "b;", "c;", "d"]
"a;b;c;d".split("(?=;)")             // Results in ["a", ";b", ";c", ";d"]
"a;b;c;d".split("((?<=;)|(?=;))")    // Results in ["a", ";", "b", ";", "c", ";", "d"]

我知道\G用于在遇到不匹配后停止。
编辑:\G用于指示最后一次匹配结束的位置(或第一次运行的字符串的开始)。感谢@SebastianProske更正了定义。

int count = 0;
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("match,");
java.util.regex.Matcher matcher = pattern.matcher("match,match,match,blabla,match,match,");
while(matcher.find())
  count++;
System.out.println(count); // Results in 5

count = 0;
pattern = java.util.regex.Pattern.compile("\\Gmatch,");
matcher = pattern.matcher("match,match,match,blabla,match,match,");
while(matcher.find())
  count++;
System.out.println(count); // Results in 3

但是在拆分内部使用时究竟是如何.split("(?<=\\G..)")工作的呢? 为什么不工作?\G
.split("(?=\\G..)")

这里有一个“在线试用”链接,用于查看上面描述的所有代码片段,以查看它们的实际效果。

标签: javaregexstringsplitmatch

解决方案


工作.split("(?<=\\G..)")原理

(?<=X)是 X 的零宽度正向回溯。\G是前一个匹配的结束(不是某种停止指令)或输入的开始,当然..是两个单独的字符。(?<=\G..)前一个匹配的结尾加上两个字符的零宽度后视也是如此。因为这是split并且我们正在描述一个delimiter,所以使整个事情成为零宽度断言意味着我们只使用它来识别在哪里中断字符串,而不是实际使用任何字符。

所以让我们来看看ABCDEF

  1. \G匹配输入的开头,并且..匹配AB,因此(?<=\G..)找到 and 之间的零宽度空间ABCD因为这是向后看:也就是说,正则表达式光标\G.. 之前AB的第一个点是和之间的点CDAB所以在和之间分割CD
  2. \G标记紧随其后的位置,AB因此找到and(?<=\G..)之间的零宽度空间,因为随着正则表达式光标向前移动,这是匹配的第一个位置:匹配and和match之间的位置。所以在和之间分割。CDEF\G..\GABCD..CDCDEF
  3. 再次相同:\G标记紧随其后的位置,CD以便找到输入和结束(?<=\G..)之间的零宽度空间。因此,在输入和结束EF之间进行拆分。EF
  4. 创建一个包含所有匹配项的数组,除了最后的空匹配项(因为这是split一个隐含的length = 0,它在最后丢弃空字符串)。

结果{ "AB", "CD", "EF" }

为什么不.split("(?=\\G..)")工作?

因为(?=X)是积极向前看。上一场比赛的结束永远不会在正则表达式光标之前。它只能在它后面


推荐阅读