Skip to content

Commit 4ca7ab9

Browse files
committed
Add Boyer-Moore-Horspool algorithm and tests.
1 parent 2be65b4 commit 4ca7ab9

File tree

4 files changed

+41
-5
lines changed

4 files changed

+41
-5
lines changed

Boyer-Moore/BoyerMoore.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
http://www.drdobbs.com/database/faster-string-searches/184408171
77
*/
88
extension String {
9-
func indexOf(pattern: String) -> String.Index? {
9+
func indexOf(pattern: String, useHorspoolImprovement: Bool = false) -> String.Index? {
1010
// Cache the length of the search pattern because we're going to
1111
// use it a few times and it's expensive to calculate.
1212
let patternLength = pattern.characters.count
@@ -53,8 +53,16 @@ extension String {
5353
// There is a possible match. Do a brute-force search backwards.
5454
if let k = backwards() { return k }
5555

56-
// If no match, we can only safely skip one character ahead.
57-
i = index(after: i)
56+
if !useHorspoolImprovement {
57+
// If no match, we can only safely skip one character ahead.
58+
i = index(after: i)
59+
}
60+
else {
61+
// Ensure to jump at least one character (this is needed because the first
62+
// character is in the skipTable, and `skipTable[lastChar] = 0`)
63+
let jumpOffset = max(skipTable[c] ?? patternLength, 1)
64+
i = index(i, offsetBy: jumpOffset, limitedBy: endIndex) ?? endIndex
65+
}
5866
} else {
5967
// The characters are not equal, so skip ahead. The amount to skip is
6068
// determined by the skip table. If the character is not present in the
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// BoyerMooreHorspoolTests.swift
3+
// Tests
4+
//
5+
// Created by Matias Mazzei on 12/24/16.
6+
// Copyright © 2016 Swift Algorithm Club. All rights reserved.
7+
//
8+
9+
class BoyerMooreHorspoolTests: BoyerMooreTest {
10+
override func setUp() {
11+
super.setUp()
12+
useHorspoolImprovement = false
13+
}
14+
}

Boyer-Moore/Tests/BoyerMooreTests.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
1+
//
2+
// BoyerMooreHorspoolTests.swift
3+
// Tests
4+
//
5+
// Created by Matias Mazzei on 12/24/16.
6+
// Copyright © 2016 Swift Algorithm Club. All rights reserved.
7+
//
8+
19
import Foundation
210
import XCTest
311

412
class BoyerMooreTest: XCTestCase {
13+
var useHorspoolImprovement = false
14+
515
override func setUp() {
616
super.setUp()
717
}
818

919
func assert(pattern: String, doesNotExistsIn string: String) {
10-
let index = string.indexOf(pattern: pattern)
20+
let index = string.indexOf(pattern: pattern, useHorspoolImprovement: useHorspoolImprovement)
1121
XCTAssertNil(index)
1222
}
1323

1424
func assert(pattern: String, existsIn string: String) {
15-
let index = string.indexOf(pattern: pattern)
25+
let index = string.indexOf(pattern: pattern, useHorspoolImprovement: useHorspoolImprovement)
1626
XCTAssertNotNil(index)
1727

1828
let startIndex = index!

Boyer-Moore/Tests/Tests.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
/* Begin PBXBuildFile section */
1010
7B80C3CE1C77A256003CECC7 /* BoyerMooreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */; };
1111
9AED567C1E0ED6DE00958DCC /* BoyerMoore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */; };
12+
9AED56801E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AED567F1E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift */; };
1213
/* End PBXBuildFile section */
1314

1415
/* Begin PBXFileReference section */
1516
7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
1617
7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
1718
7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoyerMooreTests.swift; sourceTree = SOURCE_ROOT; };
1819
9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoyerMoore.swift; path = ../../BoyerMoore.swift; sourceTree = "<group>"; };
20+
9AED567F1E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoyerMooreHorspoolTests.swift; sourceTree = SOURCE_ROOT; };
1921
/* End PBXFileReference section */
2022

2123
/* Begin PBXFrameworksBuildPhase section */
@@ -51,6 +53,7 @@
5153
9AED567B1E0ED6DE00958DCC /* BoyerMoore.swift */,
5254
7B80C3CD1C77A256003CECC7 /* BoyerMooreTests.swift */,
5355
7B2BBC941C779E7B0067B71D /* Info.plist */,
56+
9AED567F1E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift */,
5457
);
5558
name = Tests;
5659
path = TestsTests;
@@ -125,6 +128,7 @@
125128
isa = PBXSourcesBuildPhase;
126129
buildActionMask = 2147483647;
127130
files = (
131+
9AED56801E0EE60B00958DCC /* BoyerMooreHorspoolTests.swift in Sources */,
128132
9AED567C1E0ED6DE00958DCC /* BoyerMoore.swift in Sources */,
129133
7B80C3CE1C77A256003CECC7 /* BoyerMooreTests.swift in Sources */,
130134
);

0 commit comments

Comments
 (0)