简体   繁体   中英

Match the last occurrence of a word in a string

Currently, I am implementing a textbox in java swing, which highlights the keywords. I referenced to the 2nd answer given in this question . However, I want only the last occurrence of the word to be highlighted.

For example, when the user is typing "I have swimming at school at 7pm" , I want the textbox to highlight only the second "at" . I have tried using the negative lookahead in the regex. But it is not working.

I used (at(?!.at)|from|by))) instead of (at|from|by)

What I have tried (Referenced from the link provided):

  if (wordR == after || String.valueOf(text.charAt(wordR)).matches("\\W")) {
                    if (text.substring(wordL, wordR).matches("(\\W)*(at(?!.at)|from|by)"))
                        setCharacterAttributes(wordL, wordR - wordL, attr, false);
                    else
                        setCharacterAttributes(wordL, wordR - wordL, attrBlack, false);
                    wordL = wordR;
                }

I think the regex is not working as the checking is happening while the user is typing, but am not sure on how to solve this problem.

Why don't you use this method :

 public int lastIndexOf(String str) 

Returns the index within this string of the last occurrence of the specified substring, searching backward starting at the specified index.

As in:

System.out.println("index =  " + "I have swimming at school at 7pm".lastIndexOf("at"));

You can use the value returned by lastIndexOf() to set the attributes of the String in your Swing component, but obviously, you'll need to reset what you've previously done as explained here: Resetting attributes in a Document after inserting a String

If you don't do this, every occurrence of the word will remain highlighted.

Do you have to use regular expressions? indexOf has a starting position as its second parameter from where to start the search. You can just fill it with the position of the first hit. Example script:

String haystack = "I have swimming at school at 7pm";
String needle = " at ";
int pos2 = haystack.indexOf(needle, haystack.indexOf(needle) + 1);
if (pos2 > -1) {
    System.out.println("Found second '" + needle + "' at position " + pos2);
} else {
    System.out.println("Could not find second '" + needle + '"');
}

Outputs: Found second ' at ' at position 25

The procedure becomes a little more complicated if you also want to hit at. , at, , at? and at! , but the basic principle stays the same.

Basically you can use the a greedy quantifier before the word you search:

Pattern p = Pattern.compile(".*\\b(at|from|by)\\b");
String s = "I have swimming at school at 7pm";
Matcher m = p.matcher(s);
if (m.lookingAt()) {
    System.out.println(m.group(1));
}

Because .* is greedy, you obtain the last occurrence (or the first from the end of the string).

The main interest of this way is that it continues to work whatever the characters before or after the words you search like punctuation characters because the alternation is surrounded by word boundaries. Word boundaries avoid false positive for example when at is included in an other word.

Note: in a replacement context, you need to capture the start of the string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM