You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var i =self.index(startIndex, offsetBy: patternLength -1)
173
-
174
-
funcbackwards() ->String.Index? {
175
-
var q = p
176
-
var j = i
177
-
while q > pattern.startIndex {
178
-
j =index(before: j)
179
-
q =index(before: q)
180
-
ifself[j] != pattern[q] { returnnil }
181
-
}
182
-
return j
183
-
}
165
+
// Make the skip table. This table determines how far we skip ahead
166
+
// when a character from the pattern is found.
167
+
var skipTable = [Character:Int]()
168
+
for (i, c) in pattern.characters.enumerated() {
169
+
skipTable[c] = patternLength - i -1
170
+
}
184
171
185
-
while i <self.endIndex {
186
-
let c =self[i]
187
-
if c == lastChar {
188
-
iflet k =backwards() { return k }
189
-
i =index(after: i)
190
-
} else {
191
-
i =index(i, offsetBy: skipTable[c] ?? patternLength)
192
-
}
193
-
}
194
-
returnnil
172
+
// This points at the last character in the pattern.
173
+
let p = pattern.index(before: pattern.endIndex)
174
+
let lastChar = pattern[p]
175
+
176
+
// The pattern is scanned right-to-left, so skip ahead in the string by
177
+
// the length of the pattern. (Minus 1 because startIndex already points
178
+
// at the first character in the source string.)
179
+
var i =index(startIndex, offsetBy: patternLength -1)
180
+
181
+
// This is a helper function that steps backwards through both strings
182
+
// until we find a character that doesn’t match, or until we’ve reached
183
+
// the beginning of the pattern.
184
+
funcbackwards() ->Index? {
185
+
var q = p
186
+
var j = i
187
+
while q > pattern.startIndex {
188
+
j =index(before: j)
189
+
q =index(before: q)
190
+
ifself[j] != pattern[q] { returnnil }
191
+
}
192
+
return j
193
+
}
194
+
195
+
// The main loop. Keep going until the end of the string is reached.
196
+
while i < endIndex {
197
+
let c =self[i]
198
+
199
+
// Does the current character match the last character from the pattern?
200
+
if c == lastChar {
201
+
202
+
// There is a possible match. Do a brute-force search backwards.
203
+
iflet k =backwards() { return k }
204
+
205
+
// Ensure to jump at least one character (this is needed because the first
206
+
// character is in the skipTable, and `skipTable[lastChar] = 0`)
207
+
let jumpOffset =max(skipTable[c] ?? patternLength, 1)
208
+
i =index(i, offsetBy: jumpOffset, limitedBy: endIndex) ?? endIndex
209
+
} else {
210
+
// The characters are not equal, so skip ahead. The amount to skip is
211
+
// determined by the skip table. If the character is not present in the
212
+
// pattern, we can skip ahead by the full pattern length. However, if
213
+
// the character *is* present in the pattern, there may be a match up
214
+
// ahead and we can't skip as far.
215
+
i =index(i, offsetBy: skipTable[c] ?? patternLength, limitedBy: endIndex) ?? endIndex
216
+
}
217
+
}
218
+
returnnil
195
219
}
196
220
}
197
221
```
@@ -200,4 +224,4 @@ In practice, the Horspool version of the algorithm tends to perform a little bet
200
224
201
225
Credits: This code is based on the paper: [R. N. Horspool (1980). "Practical fast searching in strings". Software - Practice & Experience 10 (6): 501–506.](http://www.cin.br/~paguso/courses/if767/bib/Horspool_1980.pdf)
202
226
203
-
_Written for Swift Algorithm Club by Matthijs Hollemans, updated by Andreas Neusüß_
227
+
_Written for Swift Algorithm Club by Matthijs Hollemans, updated by Andreas Neusüß_, [Matías Mazzei](https://github.com/mmazzei).
0 commit comments