给定:
String input = "one two three four five six seven";
是否有适用于 String.split()
的正则表达式?一次捕获(最多)两个词,这样:
String[] pairs = input.split("some regex");
System.out.println(Arrays.toString(pairs));
结果:
[one two, three four, five six, seven]
这个问题是关于拆分正则表达式。这不是关于“寻找解决方法”或其他“使其以另一种方式工作”的解决方案。
最佳答案
目前(上次在 Java 17 上测试)可以使用 split()
,但在现实世界中不要使用这种方法,因为它看起来像是基于错误,因为 Java 中的后视应该有明显的最大长度,但这个解决方案使用 \w+
它不尊重此限制,并且以某种方式仍然有效 - 因此,如果它是一个将在以后的版本中修复的错误,则此解决方案将停止工作。
改为使用 Pattern
和 Matcher
带有正则表达式的类,如 \w+\s+\w+
除了更安全之外,它还避免了继承此类代码的人的维护 hell (请记住“始终编写代码,就好像最终维护您的代码的人是一个知道您住在哪里的暴力精神病患者”) .
这就是你要找的吗?
(您可以将 \\w
替换为 \\S
以包含所有非空格字符,但在本例中,我将保留 \\w
,因为使用 \\w\\s
然后 \\S\\s
更容易阅读正则表达式)
String input = "one two three four five six seven";
String[] pairs = input.split("(?<!\\G\\w+)\\s");
System.out.println(Arrays.toString(pairs));
输出:
[one two, three four, five six, seven]
\G
是上一场比赛,(?<!regex)
是消极的向后看。
在 split
我们正在努力
- 查找空格->
\\s
- 无法预测的 ->
(?<!negativeLookBehind)
- 一句话->
\\w+
- 与先前匹配的(空格)->
\\G
- 在它之前 ->
\\G\\w+
.
我一开始唯一的困惑是它如何用于第一个空格,因为我们希望忽略那个空格。 重要的信息是 \\G
at start 匹配字符串的开头 ^
.
因此,在第一次迭代之前,负后视中的正则表达式看起来像 (?<!^\\w+)
并且由于第一个空格确实有^\\w+
以前,它不能匹配拆分。下一个空间不会有这个问题,所以它会被匹配并且关于它的信息(如input
字符串中的位置)将存储在\\G
中。并稍后在下一次负面回顾中使用。
所以对于第三个空格,正则表达式将检查是否有先前匹配的空格 \\G
和字\\w+
在它之前。由于这个测试的结果是肯定的,否定的look-behind不会接受它,所以这个空间不会被匹配,但是第4个空间不会有这个问题,因为它之前的空间与存储在\\G
中的空间不同。 (在 input
字符串中会有不同的位置)。
另外,如果有人想隔开让我们说每个第三个空格,您可以使用此表单(基于 @maybeWeCouldStealAVan 的 answer,当我发布此答案片段时已删除)
input.split("(?<=\\G\\w{1,100}\\s\\w{1,100}\\s\\w{1,100})\\s")
你可以使用更大的值来代替 100,它至少是字符串中最长单词的长度。
我刚刚注意到我们也可以使用 +
而不是 {1,maxWordLength}
如果我们想用每一个奇数分割,比如每 3、5、7 个
String data = "0,0,1,2,4,5,3,4,6,1,3,3,4,5,1,1";
String[] array = data.split("(?<=\\G\\d+,\\d+,\\d+,\\d+,\\d+),");//every 5th comma
关于java - 使用 String.split() 提取单词对,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16485687/