Java中split结合\G正则的工作原理及失效原因解析
split("(?<=\\G..)")的工作原理 嘿,咱们一步步搞清楚这个正则分割的逻辑,顺便解答你为什么另一种写法行不通的问题~
首先先回顾你已经掌握的两个关键知识点:
(?<=...)是正向后顾断言:它只匹配一个位置,这个位置的前面符合括号里的正则规则,而且不会消耗任何字符串字符。\G表示上一次匹配结束的位置,第一次执行匹配时,它就指向字符串的起始位置(相当于^)。
现在把这俩结合起来,看(?<=\\G..)到底在做什么:
1. 第一次分割的定位
第一次运行split时,\G在字符串最开头。\G..就会匹配从开头开始的前两个字符(比如你的例子里就是A4)。而(?<=\\G..)则是匹配这两个字符之后的位置——也就是A4和B8之间的空隙。split在这里切割,第一个元素就是A4。
2. 循环分割的逻辑
切割完第一个元素后,\G的位置会更新到刚才切割的位置(也就是A4的末尾)。接下来,\G..会匹配从这个新位置开始的下两个字符(B8),(?<=\\G..)再次定位到这两个字符的末尾位置,split在这里切割得到第二个元素B8。
这个过程会一直重复:每次\G都承接上一次切割的终点,\G..锁定接下来的两个字符,后顾断言找到这两个字符的末尾作为切割点,直到整个字符串被拆分成一个个双字符片段。
拿你的示例字符串A4B8CUEMEWE3G6G9I1L7NZO0R2S5来说,切割过程就是:
- 切割点1:
A4之后 → 得到A4 - 切割点2:
B8之后 → 得到B8 - 切割点3:
CU之后 → 得到CU - ...以此类推,直到最后一个双字符
S5被拆分出来。
为什么split("(?=\\G..)")完全行不通?
咱们来拆解这个正向前瞻断言的情况:(?=\\G..)是匹配一个位置,要求这个位置后面的内容符合\G..的规则。
第一次切割时,\G在字符串开头,\G..匹配开头的两个字符,(?=\\G..)就会匹配字符串最开头的位置(因为这个位置后面就是A4,符合规则)。split在这里切割的话,第一个元素就是空字符串""。
更关键的是,前瞻断言不会消耗任何字符,所以切割后\G的位置还是停留在字符串开头。下一次匹配时,\G..依然匹配开头的A4,(?=\\G..)还是匹配开头位置,导致split一直在同一个位置切割,最终得到的结果要么全是空字符串,要么完全不符合我们拆分双字符的需求。
简单说,我们需要的是在每两个字符的末尾切割,后顾断言刚好能精准定位这个位置;而前瞻断言定位的是每两个字符的开头,完全搞错了切割点的位置,自然没法生效。
内容的提问来源于stack exchange,提问作者Kevin Cruijssen

