我试图匹配给定字符串中的一组短语中的任何一个或全部。这是我的正则表达式:
(^|\\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之间存在多于一个非单词字符(例如,两个或更多个空格),那么它也匹配两者。我做错了什么?
答案 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)可以通过多种方式处理。我上面的方法是使用\ b,因为它是零宽度,是一个更好的解决方案。您还可以使用其他零宽度断言,如前瞻和后观:
<?<=\W|^)...(?=\W|$)
但这基本上相当于:
\b...\b
更容易阅读。
(2)可以通过引用短语来处理。我修改了上面的代码,调用Pattern.quote()
引用任何正则表达式特殊字符。