From 3c8b3127adfd8d94333e316b038e8b3033e3292b Mon Sep 17 00:00:00 2001 From: Danny van Heumen Date: Tue, 21 Oct 2014 22:54:00 +0200 Subject: [PATCH] More precise keyword replacement: does not highlight 'fo' in "for". --- .../main/chat/replacers/KeywordReplacer.java | 27 +++- .../chat/replacers/KeywordReplacerTest.java | 143 ++++++++++++++++++ 2 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 test/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacerTest.java diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java index fd78537f9..79e4ccdc5 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java @@ -20,6 +20,21 @@ public class KeywordReplacer implements Replacer { + /** + * Index of the optional prefix group in the regex. + */ + private static final int INDEX_OPTIONAL_PREFIX_GROUP = 1; + + /** + * Index of the keyword match group in the regex. + */ + private static final int INDEX_KEYWORD_MATCH_GROUP = 2; + + /** + * Index of the optional suffix group in the regex. + */ + private static final int INDEX_OPTIONAL_SUFFIX_GROUP = 3; + /** * The keyword to highlight. */ @@ -65,15 +80,17 @@ public void replace(final StringBuilder target, final String piece) } final Matcher m = - Pattern.compile(Pattern.quote(keyword), Pattern.CASE_INSENSITIVE) - .matcher(piece); + Pattern.compile("(^|\\W)(" + Pattern.quote(keyword) + ")(\\W|$)", + Pattern.CASE_INSENSITIVE).matcher(piece); int prevEnd = 0; while (m.find()) { target.append(StringEscapeUtils.escapeHtml4(piece.substring( - prevEnd, m.start()))); - prevEnd = m.end(); - final String keywordMatch = m.group().trim(); + prevEnd, m.start() + + m.group(INDEX_OPTIONAL_PREFIX_GROUP).length()))); + prevEnd = m.end() - m.group(INDEX_OPTIONAL_SUFFIX_GROUP).length(); + final String keywordMatch = + m.group(INDEX_KEYWORD_MATCH_GROUP).trim(); target.append(""); target.append(StringEscapeUtils.escapeHtml4(keywordMatch)); target.append(""); diff --git a/test/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacerTest.java b/test/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacerTest.java new file mode 100644 index 000000000..97a660ed8 --- /dev/null +++ b/test/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacerTest.java @@ -0,0 +1,143 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat.replacers; + +import junit.framework.*; + +/** + * Tests for keyword replacer. + * + * @author Danny van Heumen + */ +public class KeywordReplacerTest + extends TestCase +{ + public void testConstructWithoutKeyword() + { + new KeywordReplacer(null); + } + + public void testConstructEmptyKeyword() + { + new KeywordReplacer(""); + } + + public void testConstructWithKeyword() + { + new KeywordReplacer("keyword"); + } + + public void testExpectPlainText() + { + KeywordReplacer replacer = new KeywordReplacer("test"); + Assert.assertTrue(replacer.expectsPlainText()); + } + + public void testNullKeywordReplacement() + { + KeywordReplacer replacer = new KeywordReplacer(null); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "this is a piece of text"); + Assert.assertEquals("this is a piece of text", target.toString()); + } + + public void testEmptyKeywordReplacement() + { + KeywordReplacer replacer = new KeywordReplacer(""); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "this is a piece of text"); + Assert.assertEquals("this is a piece of text", target.toString()); + } + + public void testTrivialKeywordReplace() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "word"); + Assert.assertEquals("word", target.toString()); + } + + public void testKeywordTooSmallForReplacement() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "wor"); + Assert.assertEquals("wor", target.toString()); + } + + public void testKeywordInSentence() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "some word in a sentence"); + Assert.assertEquals("some word in a sentence", target.toString()); + } + + public void testKeywordAtSentenceStart() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "word first in a sentence"); + Assert.assertEquals("word first in a sentence", target.toString()); + } + + public void testKeywordAtSentenceEnd() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "last in a sentence word"); + Assert.assertEquals("last in a sentence word", target.toString()); + } + + public void testKeywordInSentenceMultipleHits() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "1 word 2 word 3 word 4"); + Assert.assertEquals("1 word 2 word 3 word 4", target.toString()); + } + + public void testDontReplaceKeywordInsideWord() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "A sentence containing keywords."); + Assert.assertEquals("A sentence containing keywords.", target.toString()); + } + + public void testDontReplaceKeywordHeadingWord() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "I am the wordsmith."); + Assert.assertEquals("I am the wordsmith.", target.toString()); + } + + public void testDontReplaceKeywordTrailingWord() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "Don't find the word in keyword."); + Assert.assertEquals("Don't find the word in keyword.", target.toString()); + } + + public void testReplaceKeywordAllowPunctuation() + { + KeywordReplacer replacer = new KeywordReplacer("word"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "Find the hidden word, word. (word) between parentheses."); + Assert.assertEquals("Find the hidden word, word. (word) between parentheses.", target.toString()); + } + + public void testReplaceKeywordAllowPunctuation2() + { + KeywordReplacer replacer = new KeywordReplacer("fo"); + StringBuilder target = new StringBuilder(); + replacer.replace(target, "fo: Whenever someone writes \"for\" or any other word that starts with \"fo\" it recognizes it as my nickname ..."); + Assert.assertEquals("fo: Whenever someone writes "for" or any other word that starts with "fo" it recognizes it as my nickname ...", target.toString()); + } +}