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
+61-52Lines changed: 61 additions & 52 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,7 +32,7 @@ Here's how you could write it in Swift:
32
32
33
33
```swift
34
34
extensionString {
35
-
funcindexOf(pattern: String) ->String.Index? {
35
+
funcindexOf(pattern: String) ->String.Index? {
36
36
// Cache the length of the search pattern because we're going to
37
37
// use it a few times and it's expensive to calculate.
38
38
let patternLength = pattern.characters.count
@@ -42,57 +42,58 @@ extension String {
42
42
// Make the skip table. This table determines how far we skip ahead
43
43
// when a character from the pattern is found.
44
44
var skipTable = [Character:Int]()
45
-
for (i, c) in pattern.characters.enumerate() {
46
-
skipTable[c] = patternLength - i -1
45
+
for (i, c) in pattern.characters.enumerated() {
46
+
skipTable[c] = patternLength - i -1
47
47
}
48
48
49
49
// This points at the last character in the pattern.
50
-
let p = pattern.endIndex.predecessor()
50
+
let p =index(before: pattern.endIndex)
51
51
let lastChar = pattern[p]
52
52
53
53
// The pattern is scanned right-to-left, so skip ahead in the string by
54
54
// the length of the pattern. (Minus 1 because startIndex already points
55
55
// at the first character in the source string.)
56
-
var i =self.startIndex.advancedBy(patternLength -1)
56
+
var i =index(self.startIndex, offsetBy: patternLength -1)
57
57
58
-
// This is a helper function that steps backwards through both strings
58
+
// This is a helper function that steps backwards through both strings
59
59
// until we find a character that doesn’t match, or until we’ve reached
60
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 =index(before: j)
66
+
q =index(before: q)
67
+
ifself[j] != pattern[q] { returnnil }
68
+
}
69
+
return j
70
70
}
71
71
72
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]
75
-
76
-
// Does the current character match the last character from the pattern?
77
-
if c == lastChar {
78
-
79
-
// There is a possible match. Do a brute-force search backwards.
80
-
iflet k =backwards() { return k }
81
-
82
-
// If no match, we can only safely skip one character ahead.
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.
90
-
i =i.advancedBy(skipTable[c] ?? patternLength)
91
-
}
74
+
let c =self[i]
75
+
76
+
// Does the current character match the last character from the pattern?
77
+
if c == lastChar {
78
+
79
+
// There is a possible match. Do a brute-force search backwards.
80
+
iflet k =backwards() { return k }
81
+
82
+
// If no match, we can only safely skip one character ahead.
83
+
i =index(after: i)
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
+
i =index(i, offsetBy: skipTable[c] ?? patternLength)
91
+
}
92
92
}
93
93
returnnil
94
-
}
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:
@@ -149,34 +150,42 @@ Here's an implementation of the Boyer-Moore-Horspool algorithm:
0 commit comments