Skip to content

Commit a7a2441

Browse files
fix(strings): use case-insensitive shift table in HorspoolSearch.findFirstInsensitive (#7663)
Co-authored-by: Oleksandr Klymenko <19151554+alxkm@users.noreply.github.com>
1 parent bd64e8d commit a7a2441

2 files changed

Lines changed: 18 additions & 7 deletions

File tree

‎src/main/java/com/thealgorithms/strings/HorspoolSearch.java‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public static Integer getLastComparisons() {
9595
* @return index of first occurrence of the pattern in the text
9696
*/
9797
private static int firstOccurrence(String pattern, String text, boolean caseSensitive) {
98-
shiftValues = calcShiftValues(pattern); // build the bad symbol table
98+
shiftValues = calcShiftValues(pattern, caseSensitive); // build the bad symbol table
9999
comparisons = 0; // reset comparisons
100100

101101
if (pattern.length() == 0) { // return failure, if pattern empty
@@ -113,7 +113,7 @@ private static int firstOccurrence(String pattern, String text, boolean caseSens
113113
char patternChar = pattern.charAt(i);
114114
char textChar = text.charAt((textIndex + i) - (pattern.length() - 1));
115115
if (!charEquals(patternChar, textChar, caseSensitive)) { // bad character, shift pattern
116-
textIndex += getShiftValue(text.charAt(textIndex));
116+
textIndex += getShiftValue(text.charAt(textIndex), caseSensitive);
117117
break;
118118
}
119119
i--;
@@ -153,14 +153,15 @@ private static boolean charEquals(char c1, char c2, boolean caseSensitive) {
153153
* in the table, then it is not a rightmost occurrence, so it continues.
154154
*
155155
* @param pattern basis for the bad symbol table
156+
* @param caseSensitive whether to build the table with case-sensitive keys
156157
* @return the bad symbol table
157158
*/
158-
private static HashMap<Character, Integer> calcShiftValues(String pattern) {
159+
private static HashMap<Character, Integer> calcShiftValues(String pattern, boolean caseSensitive) {
159160
patternLength = pattern.length();
160161
HashMap<Character, Integer> table = new HashMap<>();
161162

162163
for (int i = pattern.length() - 2; i >= 0; i--) { // length - 2 is the index of the second to last character
163-
char c = pattern.charAt(i);
164+
char c = caseSensitive ? pattern.charAt(i) : Character.toLowerCase(pattern.charAt(i));
164165
int finalI = i;
165166
table.computeIfAbsent(c, k -> pattern.length() - 1 - finalI);
166167
}
@@ -173,11 +174,14 @@ private static HashMap<Character, Integer> calcShiftValues(String pattern) {
173174
* appropriate shift value for a given character
174175
*
175176
* @param c character
177+
* @param caseSensitive whether the table was built with case-sensitive keys
176178
* @return shift value that corresponds to the character argument
177179
*/
178-
private static Integer getShiftValue(char c) {
179-
if (shiftValues.get(c) != null) {
180-
return shiftValues.get(c);
180+
private static Integer getShiftValue(char c, boolean caseSensitive) {
181+
// the table holds lower-case keys for case-insensitive searches
182+
char key = caseSensitive ? c : Character.toLowerCase(c);
183+
if (shiftValues.get(key) != null) {
184+
return shiftValues.get(key);
181185
} else {
182186
return patternLength;
183187
}

‎src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ void testFindFirstInsensitiveNotMatch() {
6161
assertEquals(-1, index);
6262
}
6363

64+
@Test
65+
void testFindFirstInsensitiveWhenCaseDiffersFromPattern() {
66+
assertEquals(1, HorspoolSearch.findFirstInsensitive("AB", "xab"));
67+
assertEquals(1, HorspoolSearch.findFirstInsensitive("ab", "xAB"));
68+
assertEquals(2, HorspoolSearch.findFirstInsensitive("ba", "bbBA"));
69+
}
70+
6471
@Test
6572
void testGetLastComparisons() {
6673
HorspoolSearch.findFirst("World", "Hello World");

0 commit comments

Comments
 (0)