Matcher.find这种使用代替的繁重实现split也将起作用,尽管当您必须for为这样一个琐碎的任务编写循环时,您最好完全放弃正则表达式并使用子字符串(对于类似的编码复杂性减去 CPU 周期):
import java.util.*;
import java.util.regex.*;
public class StringSplit {
public static void main(String args[]) {
ArrayList<String> result = new ArrayList<String>();
for (Matcher m = Pattern.compile("..").matcher("12345"); m.find(result.isEmpty() ? 0 : m.start() + 1); result.add(m.group()));
System.out.println( result.toString() ); // prints "[12, 23, 34, 45]"
}
}
编辑1
match():到目前为止,没有人能够编写像您这样的正则表达式的原因BONUS_REGEX在于Matcher,它将继续寻找前一组结束的下一组(即没有重叠),而不是前一组开始的位置之后-也就是说,没有明确地重新指定开始搜索位置(上图)。一个很好的候选者BONUS_REGEX应该是"(.\\G.|^..)",但不幸的是,\G-anchor-in-the-middle 技巧不适用于 Java Match(但在 Perl 中工作得很好):
perl -e 'while ("12345"=~/(^..|.\G.)/g) { print "$1\n" }'
12
23
34
45
split():至于INSERT_REGEX_HERE一个好的候选人本来是(?<=..)(?=..)(分割点是零宽度位置,我的右边有两个字符,左边有两个字符),但同样,因为split你最终得到的没有重叠[12, 3, 45](这是接近的,但没有雪茄。)
编辑2
split()为了好玩,您可以通过首先将非边界字符加倍来欺骗做您想做的事情(这里您需要一个保留字符值来拆分):
Pattern.compile("((?<=.).(?=.))").matcher("12345").replaceAll("$1#$1").split("#")
我们可以聪明地利用零宽度前瞻断言(与后瞻断言不同)可以具有无限长度的事实来消除对保留字符的需求;因此,我们可以围绕距离双倍字符串末尾的偶数个字符(距离其开头至少两个字符)的所有点进行拆分,产生与上述相同的结果:
Pattern.compile("((?<=.).(?=.))").matcher("12345").replaceAll("$1$1").split("(?<=..)(?=(..)*$)")
或者以类似的方式欺骗match()(但不需要保留字符值):
Matcher m = Pattern.compile("..").matcher(
Pattern.compile("((?<=.).(?=.))").matcher("12345").replaceAll("$1$1")
);
while (m.find()) {
System.out.println(m.group());
} // prints "12", "23", "34", "45"