pol*_*nts 3 java regex split overlapping-matches
我正在探索正则表达式的强大功能,所以我只是想知道这样的事情是否可行:
public class StringSplit {
public static void main(String args[]) {
System.out.println(
java.util.Arrays.deepToString(
"12345".split(INSERT_REGEX_HERE)
)
); // prints "[12, 23, 34, 45]"
}
}
Run Code Online (Sandbox Code Playgroud)
如果可能的话,那么只需提供正则表达式(以及对其如何工作的先发制人的解释).
如果它只能用于Java以外的一些正则表达式,那么也可以随意提供它们.
如果不可能,请解释原因.
奖金问题
同样的问题,但有一个find()循环,而不是split:
Matcher m = Pattern.compile(BONUS_REGEX).matcher("12345");
while (m.find()) {
System.out.println(m.group());
} // prints "12", "23", "34", "45"
Run Code Online (Sandbox Code Playgroud)
请注意,并不是因为我有一个具体的任务来完成这种或那种方式,而是我想要了解正则表达式.我不需要做我想要的代码; 我想要正则表达式,如果它们存在,我可以在上面的代码中使用它来完成任务(或者使用其他版本的正则表达式,将代码"直接翻译"成另一种语言).
如果它们不存在,我想要一个很好的解释原因.
这种有点繁重的实现使用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]"
}
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
split():至于INSERT_REGEX_HERE一个好的候选者应该是(?<=..)(?=..)(分割点是零宽度位置,我的右边有两个字符,左边有两个字符),但同样,因为split你最终不会有任何重叠[12, 3, 45](这是接近的,但没有雪茄。)
为了好玩,您可以split()通过首先将非边界字符加倍来完成您想要的操作(这里您需要一个保留字符值来分割):
Pattern.compile("((?<=.).(?=.))").matcher("12345").replaceAll("$1#$1").split("#")
Run Code Online (Sandbox Code Playgroud)
我们可以聪明地利用零宽度前瞻断言(与后视不同)可以具有无限长度这一事实,消除对保留字符的需要;因此,我们可以围绕距双倍字符串末尾偶数个字符(距其开头至少两个字符)的所有点进行分割,产生与上面相同的结果:
Pattern.compile("((?<=.).(?=.))").matcher("12345").replaceAll("$1$1").split("(?<=..)(?=(..)*$)")
Run Code Online (Sandbox Code Playgroud)
或者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"
Run Code Online (Sandbox Code Playgroud)
我不认为这是可能的split(),但find()它很简单.只需使用内部捕获组的前瞻:
Matcher m = Pattern.compile("(?=(\\d\\d)).").matcher("12345");
while (m.find())
{
System.out.println(m.group(1));
}
Run Code Online (Sandbox Code Playgroud)
许多人没有意识到在比赛之后可以像任何其他捕获一样引用在前瞻或后看中捕获的文本.在这种情况下,它特别违反直觉,其中捕获是"整体"匹配的超集.
事实上,即使正则表达式整体上没有任何匹配也能正常工作.从上面的正则表达式("(?=(\\d\\d))")中删除点,你会得到相同的结果.这是因为,只要成功匹配不消耗任何字符,正则表达式引擎会在尝试再次匹配之前自动向前突然移动一个位置,以防止无限循环.
split()但是,这种技术并不等同,至少在Java中没有.虽然可以在lookarounds和其他零宽度断言拆分,有没有办法得到同样的角色出现在结果子的不止一个.
| 归档时间: |
|
| 查看次数: |
1404 次 |
| 最近记录: |