使用String.split()提取单词对

问题描述 投票:54回答:4

鉴于:

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 regex string split
4个回答
77
投票

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

相反,使用PatternMatcher类与\w+\s+\w+这样的正则表达式除了更安全之外还避免维护地狱的人将继承这样的代码(记住“总是编码好像最终维护你的代码的人是一个暴力的精神病患者谁知道你在哪里生活”)。


这是你想要的? (你可以用\\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,我们正在努力

  1. 找到空间 - > \\s
  2. 这是没有预测的 - > (?<!negativeLookBehind)
  3. 用一些词 - > \\w+
  4. 以前匹配(空间) - > \\G
  5. 在它之前 - > \\G\\w+

我开始时只有混乱,因为我们希望忽略这个空间,它对第一个空间的效果如何。重要信息是\\G在开始时匹配String ^的开头。

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

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


此外,如果有人想分开,可以说每隔3个空格就可以使用这个表格(基于@maybeWeCouldStealAVananswer,当我发布这个答案的片段时被删除了)

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

而不是100,你可以使用一些更大的值,至少是String中最长单词长度的大小。


我只是注意到我们也可以使用+而不是{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 

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个字的组的优点。


0
投票

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

  • 一个必需的单词后跟一个可选的空格(\w+\s*)
  • 重复两次{2}
  • 忽略以前匹配的字符\K
  • 所需的空间\s

-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 + "\"");
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.