Java正则表达式逻辑或

时间:2010-01-06 02:14:50

标签: java regex

我试图匹配给定字符串中的一组短语中的任何一个或全部。这是我的正则表达式:

(^|\\W)(" + phrase1 + "|" + phrase2 + "|" + phrase3 + ... ")(\\W|$)

我需要能够匹配任何数量的短语OR。它似乎工作正常,除非两个短语紧挨着彼此发生。因此"phrase1 lorem ipsum phrase2 lorem ipsum"匹配phrase1和phrase2,但"phrase1 phrase2 lorem ipsum"仅匹配phrase1("phrase1.phrase2 lorem ipsum"也是如此)。如果在phrase1和phrase2之间存在多于一个非单词字符(例如,两个或更多个空格),那么它也匹配两者。我做错了什么?

2 个答案:

答案 0 :(得分:1)

这是因为你的正则表达式的两边都有\\W。也就是说,第一个非单词字符与第一个匹配匹配,然后第二个匹配需要一个非单词字符。

答案 1 :(得分:1)

我怀疑你所追求的是:

List<String> findPhrases(String s, String... phrases) {
  return findPhrases(s, Arrays.asList(phrases));
}

List<String> findPhrases(String s, Collection<String> phrases) {
  if (phrases.size() < 1) {
    throw new IllegalArgumentException("must specify at least one phrase");
  }
  StringBuilder sb = new StringBuilder();
  Iterator<String> iter = phrases.iterator();
  String first = iter.next();
  sb.append(first);
  while (iter.hasNext()) {
    sb.append("|");
    sb.append(iter.next());
  }
  Pattern p = Pattern.compile("\\b(" + sb.toString() + ")\\b");
  Matcher m = p.matcher(s);
  List<String> ret = new ArrayList<String>();
  while (m.find()) {
    ret.append(Pattern.quote(m.group(1)));
  }
  return ret;
}

这里的一个重要区别是我使用\ b而不是\ W来分隔单词。 \ b是字符串开头的零宽度匹配,字符串的结尾或从单词字符到非单词字符的转换,反之亦然。

零宽度意味着它不会消耗来自输入的字符,如\ W确实。

编辑:您似乎遇到两个问题:

  1. \ W正在消耗您输入的字符;和
  2. 你的短语中有正则表达式的特殊字符。
  3. (1)可以通过多种方式处理。我上面的方法是使用\ b,因为它是零宽度,是一个更好的解决方案。您还可以使用其他零宽度断言,如前瞻和后观:

    <?<=\W|^)...(?=\W|$)
    

    但这基本上相当于:

    \b...\b
    

    更容易阅读。

    (2)可以通过引用短语来处理。我修改了上面的代码,调用Pattern.quote()引用任何正则表达式特殊字符。