Java replaceAll()& split()违规行为

时间:2010-10-29 08:18:24

标签: java regex string

我知道,我知道,现在我有两个问题,但这里的正则表达式意味着我不必编写两个复杂的循环。相反,我有一个只有我理解的正则表达式,我才会受雇于yonks。

我有一个字符串,比如stack.overflow.questions[0].answer[1].postDate,我需要得到[0]和[1],最好是数组。 “简单!”我的神经元惊呼,只需在输入字符串上使用正则表达式和split方法;所以我想出了这个:

String[] tokens = input.split("[^\\[\\d\\]]");

产生以下内容:

[, , , , , , , , , , , , , , , , [0], , , , , , , [1]]
亲爱的,亲爱的。所以,我想,“在这种情况下replaceAll会做什么?”:

String onlyArrayIndexes = input.replaceAll("[^\\[\\d\\]]", "");

产生:

[0][1]

嗯。为什么这样?我正在寻找一个双元素字符串数组,其中包含“[0]”作为第一个元素,“[1]”作为第二个元素。当Javadocs声明它们都按照Javadoc使用Pattern类时,为什么split在这里不起作用?

总结一下,我有两个问题:为什么split()调用产生具有看似随机空格字符的大数组我认为replaceAll正常工作是正确的,因为正则表达式替换所有不匹配“[”,数字和“]”的字符?我错过了什么意味着我希望他们产生类似的输出(好的就是三个,请不要回答“一个线索?”这个!)。

4 个答案:

答案 0 :(得分:4)

从我可以看到的split确实有效,它为您提供了一个数组,其中包含每个匹配的字符串拆分,而不是一组括号,中间有一个数字。

至于replaceAll我认为你的假设是正确的。它删除了你想要的一切(用""替换匹配)。

来自API documentation

  

将此字符串拆分为   给定的正则表达式。

     

此方法就像通过调用一样工作   两个参数的分裂方法   给定表达式和限制参数   零。尾随空字符串   因此不包括在内   结果数组。

     

字符串“boo:and:foo”,例如,   产生以下结果   这些表达方式:

Regex     Result
:     { "boo", "and", "foo" }
o     { "b", "", ":and:f" }

答案 1 :(得分:2)

这不是您问题的直接答案,但我想向您展示一个适合您需求的优秀API。

从Google Guava查看Splitter

因此,对于您的示例,您可以像这样使用它:

Iterable<String> tokens = Splitter.onPattern("[^\\[\\d\\]]").omitEmptyStrings().trimResults().split(input);

//Now you get back an Iterable which you can iterate over. Much better than an Array.
for(String s : tokens) {
   System.out.println(s);
}

这打印:
0
1

答案 2 :(得分:2)

split在您提供的正则表达式定义的边界上进行分割,因此您收到大量条目并不奇怪 - 字符串中几乎所有字符都与您的正则表达式相匹配因此,根据定义,是应该发生拆分的边界。

replaceAll 使用您提供的替代品替换正则表达式的匹配项,在您的情况下为空字符串。

如果你想抓住01,这是一个微不足道的循环:

String text = "stack.overflow.questions[0].answer[1].postDate";
Pattern pat = Pattern.compile("\\[(\\d+)\\]");
Matcher m = pat.matcher(text);
List<String> results = new ArrayList<String>();
while (m.find()) {
    results.add(m.group(1)); // Or just .group() if you want the [] as well
}
String[] tokens = results.toArray(new String[0]);

或者,如果它总是恰好两个:

String text = "stack.overflow.questions[0].answer[1].postDate";
Pattern pat = Pattern.compile(".*\\[(\\d+)\\].*\\[(\\d+)\\].*");
Matcher m = pat.matcher(text);
m.find();
String[] tokens = new String[2];
tokens[0] = m.group(1);
tokens[1] = m.group(2);

答案 3 :(得分:1)

问题是split在这里是错误的操作。

在红宝石中,我会告诉你string.scan(/\[\d+\]/),它会给你数组["[0]","[1]"]

Java没有单一方法等价物,但我们可以按如下方式编写scan方法:

public List<String> scan(String string, String regex){
   List<String> list = new ArrayList<String>();
   Pattern pattern = Pattern.compile(regex);
   Matcher matcher = pattern.matcher(string);
   while(matcher.find()) {
      list.add(matcher.group());
   }
   return retval;
}

我们可以将其称为scan(string,"\\[\\d+\\]")

等效的Scala代码是:

"""\[\d+\]""".r findAllIn string