\ G如何在.split中工作?

Kev*_*sen 10 java regex string split match

我喜欢用Java编写代码高尔夫(即使Java方式太冗长而不具竞争力),它正在以尽可能少的字节完成一定的挑战.在我的一个答案中,我有以下代码:

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

在我们将它转​​换为带有的字符串数组后,它基本上遍历2-char字符串.split.有人建议我可以把它打到这个而不是节省4个字节:

for(var p:"A4B8CUEMEWE3G6G9I1L7NZO0R2S5".split("(?<=\\G..)"))
Run Code Online (Sandbox Code Playgroud)

功能仍然相同.它循环遍历2个字符串.

但是,我们都没有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"]
Run Code Online (Sandbox Code Playgroud)

我知道\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
Run Code Online (Sandbox Code Playgroud)

但是如何在拆分中.split("(?<=\\G..)")使用时完全正常工作\G
为什么不起作用.split("(?=\\G..)")

这里是一个"尝试在线" - 链接上面描述的所有代码片段,以查看它们的实际效果.

T.J*_*der 9

怎么.split("(?<=\\G..)")工作

(?<=X)是X的零宽度正向后视\G是前一个匹配的结束(不是某种停止指令)或输入的开始,当然..是两个单独的字符.因此(?<=\G..),前一场比赛结束时的零宽度后视加上两个字符.因为这是split,我们正在描述一个分隔符,使整个事物成为零宽度断言意味着我们只使用它来识别中断字符串的位置,而不是实际消耗任何字符.

让我们来看看ABCDEF:

  1. \G匹配开始输入,并且..匹配AB,所以(?<=\G..)发现之间的零宽度空间ABCD因为这是一个反向预搜索:即,在其中存在所述第一点\G.. 之前到正则表达式光标之间的点ABCD.所以在AB和之间分开CD.
  2. \G刚过标志着位置AB,从而(?<=\G..)找到之间的零宽度的空间CDEF,因为正则表达式光标前进,这就是首先\G..匹配:\G匹配的位置AB,并CD..匹配CD.所以在CD和之间分开EF.
  3. 再次相同:\G标记位置,CD因此(?<=\G..)找到EF输入和输入结束之间的零宽度空间.因此在EF输入和输入结束之间分配.
  4. 创建一个包含所有匹配项的数组,除了末尾的空匹配(因为这是split隐式的length = 0,最后会丢弃空字符串).

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

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

因为(?=X)是积极向前看.上一次匹配的结束将永远不会超过正则表达式游标.它只能落后于它.

  • @WiktorStribiżew - 使用`\ G`的lookbehind不会消耗*任何文本.只标记应该发生分裂的位置. (2认同)

rev*_*evo 5

首先,\G定义:它是一个匹配字符串开头或上一个匹配结束的锚点.这是一个职位.它既不消耗字符也不改变光标位置.Alan Moore之前在一篇回答中写道,这种\G内部外观的行为是引擎特定的.这将在Java中以所需长度分割,但在PCRE中不会产生相同的结果.

那么,如何\G(?<=\G..)工作?请看下面逐步演示点和\G匹配的位置:

 ?A4
\G..?B8
   \G..?CU
      \G..
       .
       .
Run Code Online (Sandbox Code Playgroud)

\G匹配输入字符串的开头然后点匹配A并按4顺序.发动机继续运行并在8和之间停止C.这里有后卫比赛:

A   4   B  8
     \G .  . (?<=\G..)
Run Code Online (Sandbox Code Playgroud)

\G比赛是在以前点结束后,权相匹配,即位置4和之前B.此过程将继续到输入字符串的末尾.它将一个字符串拆分为2个单位的数据(这里安全地为一个字符).它不适用于多行输入字符串,如果是,它会部分拆分,因为点.与换行符不匹配,或者根本不拆分,因为\G它与行的开头不匹配(只是输入字符串的开头) ).

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

由于前瞻性的特点 - 前瞻性 - 它无法满足前一场比赛结束的地方.它只是继续走路,直到最后.