Java 我如何逃脱'+';在模式匹配中突出显示关键字?

Java 我如何逃脱'+';在模式匹配中突出显示关键字?,java,regex,escaping,Java,Regex,Escaping,我正在用Java实现一个关键字高亮器。我使用java.util.regex.Pattern突出显示字符串内容中的关键字(加粗)。下面的代码适用于字母数字关键字,但不适用于某些特殊字符。例如,在字符串内容中,我想突出显示具有特殊字符+(加号)的关键字c++,但它没有正确突出显示。如何转义++字符以突出显示c++ public static void main(String[] args) { String content = "java,c++,ejb,struts,j2ee,hibern

我正在用Java实现一个关键字高亮器。我使用
java.util.regex.Pattern
突出显示字符串内容中的关键字(加粗)。下面的代码适用于字母数字关键字,但不适用于某些特殊字符。例如,在字符串内容中,我想突出显示具有特殊字符+(加号)的关键字
c++
,但它没有正确突出显示。如何转义
++
字符以突出显示
c++

public static void main(String[] args)
{
    String content = "java,c++,ejb,struts,j2ee,hibernate";
    System.out.println("CONTENT: " + content);
    String highlight = "C++";

    System.out.println("HIGHLIGHT KEYWORD: " + highlight);

    //highlight = highlight.replaceAll(Pattern.quote("+"), "\\\\+");
    java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\b" + highlight + "\\b", java.util.regex.Pattern.CASE_INSENSITIVE);
    System.out.println("PATTERN: " + pattern.pattern());
    java.util.regex.Matcher matcher = pattern.matcher(content);

    while (matcher.find()) {
        System.out.println("Match found!!!");
        for (int i = 0; i <= matcher.groupCount(); i++) {
        System.out.println(matcher.group(i));
        content = matcher.replaceAll("<B>" + matcher.group(i) + "</B>");
        }
    }
    System.out.println("RESULT: " + content);
}

但我仍然无法正确理解语法。有人能帮我解决这个问题吗?

问题是
\b
单词边界锚不匹配,因为
+
是一个非单词字符,我假设后面有一个空格也是一个非单词字符

单词边界
\b
匹配从单词字符(
\w
中的成员)到非单词字符(没有
\w
的成员)的更改

此外,如果您想按字面意思匹配
+
,则必须将其转义。这里您正在搜索
C++
,这意味着至少匹配一个
C
++
是一个所有格量词,至少匹配一个
C
,并且不会回溯

试着把你的模式改成这样

java.util.regex.Pattern.compile("\\b" + highlight + "(?=\s)", java.util.regex.Pattern.CASE_INSENSITIVE);
(?=\s)
是一个积极的前瞻,它将检查在突出显示的
之后是否有空白


此外,您还需要查看您正在搜索的+。

这应该可以满足您的需要:

Pattern pattern = Pattern.compile(
    "\\b" 
    + Pattern.quote(highlight)
    + "\\b",
    Pattern.CASE_INSENSITIVE);

Update:你是对的,上面的C++不起作用(<代码> \b/COD>匹配单词边界,不承认++作为单词)。我们需要一个更复杂的解决方案:

Pattern pattern = Pattern.compile(
    "\\b" 
    + Pattern.quote(highlight)
    + "(?![^\\p{Punct}\\s])", // matches if the match is not followed by
                              // anything other than whitespace or punctuation
    Pattern.CASE_INSENSITIVE);
更新以回应评论:似乎在模式创建中需要更多的逻辑。以下是为您创建模式的帮助器方法:

private static final String WORD_BOUNDARY = "\\b";
// edit this to suit your neds:
private static final String ALLOWED = "[^,.!\\-\\s]";
private static final String LOOKAHEAD = "(?!" + ALLOWED + ")";
private static final String LOOKBEHIND = "(?<!" + ALLOWED + ")";

public static Pattern createHighlightPattern(final String highlight) {
    final Pattern pattern = Pattern.compile(
            (Character.isLetterOrDigit(highlight.charAt(0)) 
             ? WORD_BOUNDARY : LOOKBEHIND)
            + Pattern.quote(highlight)
            + (Character.isLetterOrDigit(highlight.charAt(highlight.length() - 1))
             ? WORD_BOUNDARY : LOOKAHEAD),
            Pattern.CASE_INSENSITIVE);
    return pattern;
}

当我运行此方法时,我看不到任何输出(这很好:-)

您需要的是:

Pattern.compile("\\Q"+highlight+"\\E", java.util.regex.Pattern.CASE_INSENSITIVE);

假设关键字不以标点符号开头或结尾,下面是一个注释正则表达式,它使用lookahead和lookahead来实现所需的匹配行为:

//编译正则表达式以匹配关键字或关键字短语。
java.util.regex.Pattern模式=java.util.regex.Pattern.compile(

“(?+1文档:@Tomalak实际上,更像Hm,链接本身是正确的,但很明显它在未编码的结尾部分断开了-或者你的意思是链接到Java1.6更好?@Tomalak是的,这就是我的意思(没有将直接链接添加到Pattern.quote(),lazy me)@Sean我不知道Java1.6
Pattern.quote()在哪里)
方法会比1.5中的方法更好。甚至它们各自的文档都是完全相同的;-@Gnanam,我不确定用Java,
\+
\+
@Gnanam,将我的答案和@Sean答案结合起来。他的
模式。引用(突出显示)
应该转义搜索字符串中的
+
。@Gnanam,什么不起作用?代码现在看起来如何?它做错了什么?事实上,这完全失败了,甚至没有突出显示简单的关键字,如“java”、“ejb”等。它没有突出显示关键字“c”++“代码看起来也是这样:Pattern=Pattern.compile(“\\b”+Pattern.quote(highlight)+”(?=\\s)”,java.util.regex.Pattern.CASE\u不区分大小写);@stema+1用于您的方法,但我认为OP的字符串中没有空格,所以您必须用一个负数替换正的前瞻(如我的回答中所示)我要突出显示的关键字应该是“独立”单词,而不是较大单词的一部分。例如,如果有一个字符串内容包含“java,javascript”,而我的关键字是“java”,则您的模式将在此处同时突出显示java和javascript。输出为:
java,javascript
然后用\\b…将其包围起来,如下所示:
java.util.regex.pattern.compile(“\\b\\Q”+highlight+”\\E\\b”,java.util.regex.pattern.不区分大小写)
即使尝试了
\\b
,它也没有突出显示关键字
c++
。是的!Sean的答案在这里似乎做得很好!但它也不完美。我认为您将不得不使用传统的拆分和检查单个字符串的方法!但还是让我们想想吧!
private static void testMatch(final String haystack, final String needle) {
    final Matcher matcher = createHighlightPattern(needle).matcher(haystack);
    if (!matcher.find())
        System.out.println("Failed to find pattern " + needle);
    while (matcher.find())
        System.out.println("Found additional match: " + matcher.group() +
                           " for pattern " + needle);
}

public static void main(final String[] args) {
    final String testString = "java,c++,hibernate,.net,asp.net,c#,spring";
    testMatch(testString, "java");
    testMatch(testString, "c++");
    testMatch(testString, ".net");
    testMatch(testString, "c#");
}
Pattern.compile("\\Q"+highlight+"\\E", java.util.regex.Pattern.CASE_INSENSITIVE);