From 92513ba6ae0d521ede1a172d4dedade92ba607cd Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 16 Sep 2016 13:00:31 +0200 Subject: [PATCH] Find unicode support (IDEA-112749) --- .../intellij/util/text/StringSearcher.java | 54 ++++++++++++------- .../util/text/StringSearcherTest.java | 25 +++++++++ 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/platform/util/src/com/intellij/util/text/StringSearcher.java b/platform/util/src/com/intellij/util/text/StringSearcher.java index 51345db80b68..493894ff6d7a 100644 --- a/platform/util/src/com/intellij/util/text/StringSearcher.java +++ b/platform/util/src/com/intellij/util/text/StringSearcher.java @@ -31,6 +31,7 @@ public class StringSearcher { private final int myPatternLength; private final int[] mySearchTable = new int[128]; private final boolean myCaseSensitive; + private final boolean myLowecaseTransform; private final boolean myForwardDirection; private final boolean myJavaIdentifier; private final boolean myHandleEscapeSequences; @@ -57,7 +58,14 @@ public class StringSearcher { myPattern = pattern; myCaseSensitive = caseSensitive; myForwardDirection = forwardDirection; - myPatternArray = myCaseSensitive ? myPattern.toCharArray() : myPattern.toLowerCase(Locale.US).toCharArray(); + char[] chars = myCaseSensitive ? myPattern.toCharArray() : myPattern.toLowerCase(Locale.US).toCharArray(); + if (chars.length != myPattern.length()) { + myLowecaseTransform = false; + chars = myPattern.toUpperCase(Locale.US).toCharArray(); + } else { + myLowecaseTransform = true; + } + myPatternArray = chars; myPatternLength = myPatternArray.length; Arrays.fill(mySearchTable, -1); myJavaIdentifier = lookForJavaIdentifiersOnlyIfPossible && @@ -113,18 +121,13 @@ public class StringSearcher { while (start <= end) { int i = myPatternLength - 1; - char lastChar = textArray != null ? textArray[start + i] : text.charAt(start + i); - if (!myCaseSensitive) { - lastChar = StringUtil.toLowerCase(lastChar); - } - if (myPatternArray[i] == lastChar) { + char lastChar = normalizedCharAt(text, textArray, start + i); + + if (isSameChar(myPatternArray[i], lastChar)) { i--; while (i >= 0) { char c = textArray != null ? textArray[start + i] : text.charAt(start + i); - if (!myCaseSensitive) { - c = StringUtil.toLowerCase(c); - } - if (myPatternArray[i] != c) break; + if (!isSameChar(myPatternArray[i], c)) break; i--; } if (i < 0) { @@ -152,18 +155,13 @@ public class StringSearcher { int end = _end + 1; while (start <= end - myPatternLength + 1) { int i = myPatternLength - 1; - char lastChar = textArray != null ? textArray[end - (start + i)] : text.charAt(end - (start + i)); - if (!myCaseSensitive) { - lastChar = StringUtil.toLowerCase(lastChar); - } - if (myPatternArray[myPatternLength - 1 - i] == lastChar) { + char lastChar = normalizedCharAt(text, textArray, end - (start + i)); + + if (isSameChar(myPatternArray[myPatternLength - 1 - i], lastChar)) { i--; while (i >= 0) { char c = textArray != null ? textArray[end - (start + i)] : text.charAt(end - (start + i)); - if (!myCaseSensitive) { - c = StringUtil.toLowerCase(c); - } - if (myPatternArray[myPatternLength - 1 - i] != c) break; + if (!isSameChar(myPatternArray[myPatternLength - 1 - i], c)) break; i--; } if (i < 0) return end - start - myPatternLength + 1; @@ -186,6 +184,22 @@ public class StringSearcher { } } + private char normalizedCharAt(@NotNull CharSequence text, @Nullable char[] textArray, int index) { + char lastChar = textArray != null ? textArray[index] : text.charAt(index); + if (myCaseSensitive) { + return lastChar; + } + return myLowecaseTransform ? StringUtil.toLowerCase(lastChar) : StringUtil.toUpperCase(lastChar); + } + + private boolean isSameChar(char charInPattern, char charInText) { + boolean sameChar = charInPattern == charInText; + if (!sameChar && !myCaseSensitive) { + return StringUtil.charsEqualIgnoreCase(charInPattern, charInText); + } + return sameChar; + } + /** * @deprecated Use {@link #scan(CharSequence)} instead */ @@ -207,6 +221,7 @@ public class StringSearcher { StringSearcher searcher = (StringSearcher)o; if (myCaseSensitive != searcher.myCaseSensitive) return false; + if (myLowecaseTransform != searcher.myLowecaseTransform) return false; if (myForwardDirection != searcher.myForwardDirection) return false; if (myJavaIdentifier != searcher.myJavaIdentifier) return false; if (myHandleEscapeSequences != searcher.myHandleEscapeSequences) return false; @@ -217,6 +232,7 @@ public class StringSearcher { public int hashCode() { int result = myPattern.hashCode(); result = 31 * result + (myCaseSensitive ? 1 : 0); + result = 31 * result + (myLowecaseTransform ? 1 : 0); result = 31 * result + (myForwardDirection ? 1 : 0); result = 31 * result + (myJavaIdentifier ? 1 : 0); result = 31 * result + (myHandleEscapeSequences ? 1 : 0); diff --git a/platform/util/testSrc/com/intellij/util/text/StringSearcherTest.java b/platform/util/testSrc/com/intellij/util/text/StringSearcherTest.java index d1ef712f260c..2a7da1891d81 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringSearcherTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringSearcherTest.java @@ -32,4 +32,29 @@ public class StringSearcherTest extends TestCase { assertEquals(text.indexOf("bc"), index); } + public void testCaseInsensitiveWithUnicode() { + String pattern = "SİL"; + final String text = "SİL SIL"; + final int firstPos = text.indexOf(pattern); + final int secondPos = text.indexOf("SIL"); + + StringSearcher searcher = new StringSearcher(pattern, false, true); + int index = searcher.scan(text); + + assertEquals(firstPos, index); + assertEquals(secondPos, searcher.scan(text, index + 1, text.length())); + pattern = "sil"; + + searcher = new StringSearcher(pattern, false, true); + index = searcher.scan(text); + + assertEquals(firstPos, index); + assertEquals(secondPos, searcher.scan(text, index + 1, text.length())); + + searcher = new StringSearcher(pattern, false, false); + index = searcher.scan(text, 0, text.length()); + + assertEquals(secondPos, index); + assertEquals(firstPos, searcher.scan(text, 0, index - 1)); + } }