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
Copy file name to clipboardExpand all lines: Boyer-Moore/README.markdown
+41-40Lines changed: 41 additions & 40 deletions
Original file line number
Diff line number
Diff line change
@@ -9,14 +9,14 @@ For example:
9
9
```swift
10
10
// Input:
11
11
let s ="Hello, World"
12
-
s.indexOf("World")
12
+
s.indexOf(pattern: "World")
13
13
14
14
// Output:
15
15
<String.Index?>7
16
16
17
17
// Input:
18
18
let animals ="🐶🐔🐷🐮🐱"
19
-
animals.indexOf("🐮")
19
+
animals.indexOf(pattern: "🐮")
20
20
21
21
// Output:
22
22
<String.Index?>6
@@ -32,67 +32,68 @@ Here's how you could write it in Swift:
32
32
33
33
```swift
34
34
extensionString {
35
-
funcindexOf(pattern: String) ->String.Index? {
36
-
// Cache the length of the search pattern because we're going to
37
-
// use it a few times and it's expensive to calculate.
35
+
funcindexOf(pattern: String) ->String.Index? {
36
+
// Cache the length of the search pattern because we're going to
37
+
// use it a few times and it's expensive to calculate.
38
38
let patternLength = pattern.characters.count
39
-
assert(patternLength >0)
40
-
assert(patternLength <=self.characters.count)
39
+
assert(patternLength >0)
40
+
assert(patternLength <=self.characters.count)
41
41
42
-
// Make the skip table. This table determines how far we skip ahead
43
-
// when a character from the pattern is found.
42
+
// Make the skip table. This table determines how far we skip ahead
43
+
// when a character from the pattern is found.
44
44
var skipTable = [Character:Int]()
45
45
for (i, c) in pattern.characters.enumerate() {
46
-
skipTable[c] = patternLength - i -1
46
+
skipTable[c] = patternLength - i -1
47
47
}
48
48
49
-
// This points at the last character in the pattern.
49
+
// This points at the last character in the pattern.
50
50
let p = pattern.endIndex.predecessor()
51
51
let lastChar = pattern[p]
52
52
53
-
// The pattern is scanned right-to-left, so skip ahead in the string by
54
-
// the length of the pattern. (Minus 1 because startIndex already points
55
-
// at the first character in the source string.)
53
+
// The pattern is scanned right-to-left, so skip ahead in the string by
54
+
// the length of the pattern. (Minus 1 because startIndex already points
55
+
// at the first character in the source string.)
56
56
var i =self.startIndex.advancedBy(patternLength -1)
57
57
58
-
// This is a helper function that steps backwards through both strings
59
-
// until we find a character that doesn’t match, or until we’ve reached
60
-
// the beginning of the pattern.
58
+
// This is a helper function that steps backwards through both strings
59
+
// until we find a character that doesn’t match, or until we’ve reached
60
+
// the beginning of the pattern.
61
61
funcbackwards() ->String.Index? {
62
-
var q = p
63
-
var j = i
64
-
while q > pattern.startIndex {
65
-
j = j.predecessor()
66
-
q = q.predecessor()
67
-
ifself[j] != pattern[q] { returnnil }
68
-
}
69
-
return j
62
+
var q = p
63
+
var j = i
64
+
while q > pattern.startIndex {
65
+
j = j.predecessor()
66
+
q = q.predecessor()
67
+
ifself[j] != pattern[q] { returnnil }
68
+
}
69
+
return j
70
70
}
71
71
72
-
// The main loop. Keep going until the end of the string is reached.
72
+
// The main loop. Keep going until the end of the string is reached.
73
73
while i <self.endIndex {
74
-
let c =self[i]
74
+
let c =self[i]
75
75
76
-
// Does the current character match the last character from the pattern?
77
-
if c == lastChar {
76
+
// Does the current character match the last character from the pattern?
77
+
if c == lastChar {
78
78
79
-
// There is a possible match. Do a brute-force search backwards.
79
+
// There is a possible match. Do a brute-force search backwards.
80
80
iflet k =backwards() { return k }
81
81
82
-
// If no match, we can only safely skip one character ahead.
82
+
// If no match, we can only safely skip one character ahead.
83
83
i = i.successor()
84
-
} else {
85
-
// The characters are not equal, so skip ahead. The amount to skip is
86
-
// determined by the skip table. If the character is not present in the
87
-
// pattern, we can skip ahead by the full pattern length. However, if
88
-
// the character *is* present in the pattern, there may be a match up
89
-
// ahead and we can't skip as far.
84
+
} else {
85
+
// The characters are not equal, so skip ahead. The amount to skip is
86
+
// determined by the skip table. If the character is not present in the
87
+
// pattern, we can skip ahead by the full pattern length. However, if
88
+
// the character *is* present in the pattern, there may be a match up
89
+
// ahead and we can't skip as far.
90
90
i = i.advancedBy(skipTable[c] ?? patternLength)
91
-
}
91
+
}
92
92
}
93
-
returnnil
94
-
}
93
+
returnnil
94
+
}
95
95
}
96
+
96
97
```
97
98
98
99
The algorithm works as follows. You line up the search pattern with the source string and see what character from the string matches the *last* character of the search pattern:
0 commit comments