簡體   English   中英

如何在模式匹配中轉義“+”以突出顯示關鍵字?

[英]How do I escape '+' in pattern matching to highlight keyword?

我在 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);
}

Output:
內容:java,c++,ejb,struts,j2ee,hibernate
重點關鍵字:C++
模式:\bC++\b
匹配找到了!!!
c
結果:java、 c ++、ejb、struts、j2ee、hibernate


我什至嘗試在像這樣調用Pattern.compile之前轉義“+”,

 highlight = highlight.replaceAll(Pattern.quote("+"), "\\\\+");

但我仍然無法正確使用語法。 有人可以幫我解決這個問題嗎?

這應該做你需要的:

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

更新:你是對的,以上不適用於 C++ ( \b匹配單詞邊界並且不將 ++ 識別為單詞)。 我們需要一個更復雜的解決方案:

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;
}

這里有一些測試代碼來檢查它是否有效:

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#");
}

當我運行這個方法時,我沒有看到任何 output (這很好:-))

問題是\b單詞邊界錨不匹配,因為+是非單詞字符,我假設后面有一個空格也是非單詞字符。

單詞邊界\b匹配從單詞字符( \w中的成員)到非單詞字符(沒有\w成員)的變化。

此外,如果您想從字面上匹配+ ,則必須將其轉義。 在這里,您正在搜索C++ ,這意味着匹配至少一個C並且++是一個所有格量詞,匹配至少 1 個C並且不回溯。

嘗試將您的模式更改為這樣的

java.util.regex.Pattern.compile("\\b" + highlight + "(?=\s)", java.util.regex.Pattern.CASE_INSENSITIVE);

(?=\s)是一個積極的前瞻,它將檢查您的highlight后是否有空格

此外,您將需要轉義您正在搜索的 +。

你需要的都在這里:

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

假設您的關鍵字不以標點符號開頭或結尾,這里有一個注釋正則表達式,它使用前瞻和后瞻來實現您想要的匹配行為:

// Compile regex to match a keyword or keyphrase.
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
    "(?<=[\\s'\".?!,;:]|^)  # Word preceded by ws, quote, punct or BOS.\n" +

    // Escape any regex metacharacters in the keyword phrase.
    java.util.regex.Pattern.quote(highlight) + " # Keyword to be matched.\n" +

    "(?=[\\s'\".?!,;:]|$)   # Word followed by ws, quote, punct or EOS.", 
    Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS);

請注意,即使您的關鍵字是包含空格的短語,此解決方案也有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM