Skip to content

Commit cf5ca9c

Browse files
committed
Updated to Swift 3.
Updated to Swift 3 Syntax. The .swift file wasn’t converted yet. Additionally, I fixed a bug in there.
1 parent 24b721a commit cf5ca9c

File tree

4 files changed

+209
-178
lines changed

4 files changed

+209
-178
lines changed

Boyer-Moore/BoyerMoore.playground/Contents.swift

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,66 @@
11
//: Playground - noun: a place where people can play
22

33
extension String {
4-
func indexOf(pattern: String) -> String.Index? {
5-
let patternLength = pattern.characters.count
6-
assert(patternLength > 0)
7-
assert(patternLength <= self.characters.count)
8-
9-
var skipTable = [Character: Int]()
10-
for (i, c) in pattern.characters.enumerated() {
11-
skipTable[c] = patternLength - i - 1
12-
}
13-
14-
let p = pattern.index(before: pattern.endIndex)
15-
let lastChar = pattern[p]
16-
var i = self.index(startIndex, offsetBy: patternLength - 1)
17-
18-
func backwards() -> String.Index? {
19-
var q = p
20-
var j = i
21-
while q > pattern.startIndex {
22-
j = index(before: j)
23-
q = index(before: q)
24-
if self[j] != pattern[q] { return nil }
25-
}
26-
return j
27-
}
28-
29-
while i < self.endIndex {
30-
let c = self[i]
31-
if c == lastChar {
32-
if let k = backwards() { return k }
33-
i = index(after: i)
34-
} else {
35-
i = index(i, offsetBy: skipTable[c] ?? patternLength)
36-
}
4+
func indexOf(pattern: String) -> String.Index? {
5+
// Cache the length of the search pattern because we're going to
6+
// use it a few times and it's expensive to calculate.
7+
let patternLength = pattern.characters.count
8+
assert(patternLength > 0)
9+
assert(patternLength <= self.characters.count)
10+
11+
// Make the skip table. This table determines how far we skip ahead
12+
// when a character from the pattern is found.
13+
var skipTable = [Character: Int]()
14+
for (i, c) in pattern.characters.enumerated() {
15+
skipTable[c] = patternLength - i - 1
16+
}
17+
18+
// This points at the last character in the pattern.
19+
let p = pattern.index(before: pattern.endIndex)
20+
let lastChar = pattern[p]
21+
22+
// The pattern is scanned right-to-left, so skip ahead in the string by
23+
// the length of the pattern. (Minus 1 because startIndex already points
24+
// at the first character in the source string.)
25+
var i = self.index(startIndex, offsetBy: patternLength - 1)
26+
27+
// This is a helper function that steps backwards through both strings
28+
// until we find a character that doesn’t match, or until we’ve reached
29+
// the beginning of the pattern.
30+
func backwards() -> String.Index? {
31+
var q = p
32+
var j = i
33+
while q > pattern.startIndex {
34+
j = index(before: j)
35+
q = index(before: q)
36+
if self[j] != pattern[q] { return nil }
37+
}
38+
return j
39+
}
40+
41+
// The main loop. Keep going until the end of the string is reached.
42+
while i < self.endIndex {
43+
let c = self[i]
44+
45+
// Does the current character match the last character from the pattern?
46+
if c == lastChar {
47+
48+
// There is a possible match. Do a brute-force search backwards.
49+
if let k = backwards() { return k }
50+
51+
// If no match, we can only safely skip one character ahead.
52+
i = index(after: i)
53+
} else {
54+
// The characters are not equal, so skip ahead. The amount to skip is
55+
// determined by the skip table. If the character is not present in the
56+
// pattern, we can skip ahead by the full pattern length. However, if
57+
// the character *is* present in the pattern, there may be a match up
58+
// ahead and we can't skip as far.
59+
i = self.index(i, offsetBy: skipTable[c] ?? patternLength)
60+
}
61+
}
62+
return nil
3763
}
38-
return nil
39-
}
4064
}
4165

4266
// A few simple tests

Boyer-Moore/BoyerMoore.playground/timeline.xctimeline

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
version = "3.0">
44
<TimelineItems>
55
<LoggerValueHistoryTimelineItem
6-
documentLocation = "#CharacterRangeLen=1&amp;CharacterRangeLoc=345&amp;EndingColumnNumber=37&amp;EndingLineNumber=9&amp;StartingColumnNumber=9&amp;StartingLineNumber=9&amp;Timestamp=497585369.829471"
6+
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=75&amp;EndingColumnNumber=37&amp;EndingLineNumber=3&amp;StartingColumnNumber=9&amp;StartingLineNumber=3&amp;Timestamp=503226447.616217"
77
selectedRepresentationIndex = "0"
88
shouldTrackSuperviewWidth = "NO">
99
</LoggerValueHistoryTimelineItem>
1010
<LoggerValueHistoryTimelineItem
11-
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=345&amp;EndingColumnNumber=26&amp;EndingLineNumber=9&amp;StartingColumnNumber=9&amp;StartingLineNumber=9&amp;Timestamp=497585369.82964"
11+
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=75&amp;EndingColumnNumber=26&amp;EndingLineNumber=3&amp;StartingColumnNumber=9&amp;StartingLineNumber=3&amp;Timestamp=503226447.61657"
1212
selectedRepresentationIndex = "0"
1313
shouldTrackSuperviewWidth = "NO">
1414
</LoggerValueHistoryTimelineItem>
1515
<LoggerValueHistoryTimelineItem
16-
documentLocation = "#CharacterRangeLen=1&amp;CharacterRangeLoc=345&amp;EndingColumnNumber=25&amp;EndingLineNumber=9&amp;StartingColumnNumber=9&amp;StartingLineNumber=9&amp;Timestamp=497585369.82978"
16+
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=75&amp;EndingColumnNumber=25&amp;EndingLineNumber=3&amp;StartingColumnNumber=9&amp;StartingLineNumber=3&amp;Timestamp=503226447.616725"
1717
selectedRepresentationIndex = "0"
1818
shouldTrackSuperviewWidth = "NO">
1919
</LoggerValueHistoryTimelineItem>

Boyer-Moore/BoyerMoore.swift

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,64 +6,64 @@
66
http://www.drdobbs.com/database/faster-string-searches/184408171
77
*/
88
extension String {
9-
func indexOf(pattern: String) -> String.Index? {
10-
// Cache the length of the search pattern because we're going to
11-
// use it a few times and it's expensive to calculate.
12-
let patternLength = pattern.characters.count
13-
assert(patternLength > 0)
14-
assert(patternLength <= self.characters.count)
15-
16-
// Make the skip table. This table determines how far we skip ahead
17-
// when a character from the pattern is found.
18-
var skipTable = [Character: Int]()
19-
for (i, c) in pattern.characters.enumerate() {
20-
skipTable[c] = patternLength - i - 1
21-
}
22-
23-
// This points at the last character in the pattern.
24-
let p = pattern.endIndex.predecessor()
25-
let lastChar = pattern[p]
26-
27-
// The pattern is scanned right-to-left, so skip ahead in the string by
28-
// the length of the pattern. (Minus 1 because startIndex already points
29-
// at the first character in the source string.)
30-
var i = self.startIndex.advancedBy(patternLength - 1)
31-
32-
// This is a helper function that steps backwards through both strings
33-
// until we find a character that doesn’t match, or until we’ve reached
34-
// the beginning of the pattern.
35-
func backwards() -> String.Index? {
36-
var q = p
37-
var j = i
38-
while q > pattern.startIndex {
39-
j = j.predecessor()
40-
q = q.predecessor()
41-
if self[j] != pattern[q] { return nil }
42-
}
43-
return j
44-
}
45-
46-
// The main loop. Keep going until the end of the string is reached.
47-
while i < self.endIndex {
48-
let c = self[i]
49-
50-
// Does the current character match the last character from the pattern?
51-
if c == lastChar {
52-
53-
// There is a possible match. Do a brute-force search backwards.
54-
if let k = backwards() { return k }
55-
56-
// If no match, we can only safely skip one character ahead.
57-
i = i.successor()
58-
} else {
59-
// The characters are not equal, so skip ahead. The amount to skip is
60-
// determined by the skip table. If the character is not present in the
61-
// pattern, we can skip ahead by the full pattern length. However, if
62-
// the character *is* present in the pattern, there may be a match up
63-
// ahead and we can't skip as far.
64-
i = i.advancedBy(skipTable[c] ?? patternLength)
65-
}
9+
func indexOf(pattern: String) -> String.Index? {
10+
// Cache the length of the search pattern because we're going to
11+
// use it a few times and it's expensive to calculate.
12+
let patternLength = pattern.characters.count
13+
assert(patternLength > 0)
14+
assert(patternLength <= self.characters.count)
15+
16+
// Make the skip table. This table determines how far we skip ahead
17+
// when a character from the pattern is found.
18+
var skipTable = [Character: Int]()
19+
for (i, c) in pattern.characters.enumerated() {
20+
skipTable[c] = patternLength - i - 1
21+
}
22+
23+
// This points at the last character in the pattern.
24+
let p = pattern.index(before: pattern.endIndex)
25+
let lastChar = pattern[p]
26+
27+
// The pattern is scanned right-to-left, so skip ahead in the string by
28+
// the length of the pattern. (Minus 1 because startIndex already points
29+
// at the first character in the source string.)
30+
var i = self.index(startIndex, offsetBy: patternLength - 1)
31+
32+
// This is a helper function that steps backwards through both strings
33+
// until we find a character that doesn’t match, or until we’ve reached
34+
// the beginning of the pattern.
35+
func backwards() -> String.Index? {
36+
var q = p
37+
var j = i
38+
while q > pattern.startIndex {
39+
j = index(before: j)
40+
q = index(before: q)
41+
if self[j] != pattern[q] { return nil }
42+
}
43+
return j
44+
}
45+
46+
// The main loop. Keep going until the end of the string is reached.
47+
while i < self.endIndex {
48+
let c = self[i]
49+
50+
// Does the current character match the last character from the pattern?
51+
if c == lastChar {
52+
53+
// There is a possible match. Do a brute-force search backwards.
54+
if let k = backwards() { return k }
55+
56+
// If no match, we can only safely skip one character ahead.
57+
i = index(after: i)
58+
} else {
59+
// The characters are not equal, so skip ahead. The amount to skip is
60+
// determined by the skip table. If the character is not present in the
61+
// pattern, we can skip ahead by the full pattern length. However, if
62+
// the character *is* present in the pattern, there may be a match up
63+
// ahead and we can't skip as far.
64+
i = self.index(i, offsetBy: skipTable[c] ?? patternLength)
65+
}
66+
}
67+
return nil
6668
}
67-
return nil
68-
}
6969
}

0 commit comments

Comments
 (0)