57

鉴于:

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]

这个问题是关于拆分正则表达式的。这不是关于“找到解决方法”或其他“使其以另一种方式工作”的解决方案。

4

4 回答 4

80

目前(最后在 Java 14 上测试)可以用 来做split(),但在现实世界中不要使用这种方法,因为它看起来像是基于错误,因为 Java 中的后视应该有明显的最大长度,但是这个解决方案\w+不遵守此限制并且以某种方式仍然有效的用途- 因此,如果它是一个将在以后的版本中修复的错误,则此解决方案将停止工作。

取而代之的是使用PatternMatcher带有正则表达式的类\w+\s+\w+,除了更安全之外,还可以避免继承此类代码的人的维护地狱(请记住“始终编写代码,就好像最终维护您的代码的人是一个知道您住在哪里的暴力精神病患者”) .


这是你想要的?
(您可以替换\\w\\S以包含所有非空格字符,但对于此示例,我将离开,因为使用then\\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我们试图

  1. 查找空格->\\s
  2. 未预测的->(?<!negativeLookBehind)
  3. 一句话—​​—>\\w+
  4. 与先前匹配的(空格)->\\G
  5. 在它之前 -> \\G\\w+

我一开始唯一的困惑是它如何用于第一个空格,因为我们希望忽略那个空格。重要信息是\\Gat start 匹配 String 的开头^

因此,在第一次迭代正则表达式之前,负后视会看起来像(?<!^\\w+),并且由于第一个空间之前确实^\\w+,它不能匹配拆分。下一个空间不会有这个问题,所以它会被匹配并且关于它的信息(比如它在字符串中的位置input)将被存储\\G并在以后的下一个否定后视中使用。

因此,对于第三个空格,正则表达式将检查之前是否有先前匹配的空格\\G和单词\\w+。由于这个测试的结果是肯定的,否定的后视不会接受它,所以这个空间不会被匹配,但是第 4 个空间不会有这个问题,因为它之前的空间不会与存储的相同\\G(它将在input字符串中具有不同的位置) .


另外,如果有人想分开让我们说每个第三个空格,您可以使用此表格(基于@maybeWeCouldStealAVan答案,当我发布此答案片段时该答案已被删除)

input.split("(?<=\\G\\w{1,100}\\s\\w{1,100}\\s\\w{1,100})\\s")

您可以使用更大的值代替 100,它至少是字符串中最长单词长度的大小。


我刚刚注意到,如果我们想用每个奇数分割,例如每 3、5、7 个,我们也可以使用+而不是{1,maxWordLength}

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 
于 2013-05-10T16:04:58.333 回答
9

这将起作用,但需要提前设置最大字长:

String input = "one two three four five six seven eight nine ten eleven";
String[] pairs = input.split("(?<=\\G\\S{1,30}\\s\\S{1,30})\\s");
System.out.println(Arrays.toString(pairs));

我更喜欢 Pshemo 的答案,它更短且可用于任意字长,但这(正如@Pshemo 指出的那样)具有适用于超过 2 个字的组的优点。

于 2013-05-10T16:05:45.267 回答
0

这对我有用这里(\w+\s*){2}\K\s的 例子

  • 一个必需的单词,后跟一个可选的空格(\w+\s*)
  • 重复两次{2}
  • 忽略以前匹配的字符\K
  • 所需空间 \s
于 2013-09-12T22:42:37.063 回答
-1

你可以试试这个:

[a-z]+\s[a-z]+

更新:

([a-z]+\s[a-z]+)|[a-z]+

在此处输入图像描述

更新:

 String pattern = "([a-z]+\\s[a-z]+)|[a-z]+";
 String input = "one two three four five six seven";

 Pattern splitter = Pattern.compile(pattern);
 String[] results = splitter.split(input);

 for (String pair : results) {
 System.out.println("Output = \"" + pair + "\"");
于 2013-05-10T15:31:20.137 回答