Skip to content

Commit 8bf8fe0

Browse files
committed
Release 0.0.1
1 parent 60841fb commit 8bf8fe0

File tree

8 files changed

+379
-3
lines changed

8 files changed

+379
-3
lines changed

.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Xcode
2+
#
3+
build/
4+
*.pbxuser
5+
!default.pbxuser
6+
*.mode1v3
7+
!default.mode1v3
8+
*.mode2v3
9+
!default.mode2v3
10+
*.perspectivev3
11+
!default.perspectivev3
12+
xcuserdata
13+
*.xccheckout
14+
*.moved-aside
15+
DerivedData
16+
*.hmap
17+
*.ipa
18+
*.xcuserstate
19+
20+
# CocoaPods
21+
#
22+
# We recommend against adding the Pods directory to your .gitignore. However
23+
# you should judge for yourself, the pros and cons are mentioned at:
24+
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
25+
#
26+
# Pods/
27+
28+
# Carthage
29+
#
30+
# Add this line if you want to avoid checking in source code from Carthage dependencies.
31+
# Carthage/Checkouts
32+
33+
Carthage/Build

LICENSE

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
The MIT License (MIT)
2-
3-
Copyright (c) 2016 Mark Hamilton
1+
Copyright (c) 2016 Mark Hamilton / dryverless (http://www.dryverless.com)
42

53
Permission is hereby granted, free of charge, to any person obtaining a copy
64
of this software and associated documentation files (the "Software"), to deal

Pod/Assets/.gitkeep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

Pod/Classes/.gitkeep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,85 @@
11
# SwiftyLevenshtein
22
Levenshtein distance algorithm written in Swift 2.2. Both a slow and highly optimized version are included.
3+
4+
##Usage
5+
6+
```swift
7+
var source_string = "x men"
8+
var target_string = "x mn"
9+
10+
11+
source_string.getLevenshtein(target_string) // 1
12+
target_string.getLevenshtein(source_string) // 1
13+
14+
//source_string.getSlowLevenshtein(target_string) // 1
15+
//target_string.getSlowLevenshtein(source_string) // 1
16+
17+
//levenshtein(source_string, target: target_string) // 1
18+
19+
//slowlevenshtein(source_string, target: target_string) // 1
20+
```
21+
22+
##CocoaPods
23+
24+
[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
25+
26+
```bash
27+
$ gem install cocoapods
28+
```
29+
30+
> CocoaPods 0.39.0+ is required to build SwiftyLevenshtein 0.0.1+.
31+
32+
To integrate SwiftyLevenshtein into your Xcode project using CocoaPods, specify it in your `Podfile`:
33+
34+
```ruby
35+
source 'https://github.com/CocoaPods/Specs.git'
36+
platform :ios, '8.0'
37+
use_frameworks!
38+
39+
pod 'SwiftyLevenshtein', '~> 0.0.1'
40+
```
41+
42+
Then, run the following command:
43+
44+
```bash
45+
$ pod install
46+
```
47+
48+
##Related Projects:
49+
50+
###Example Swift Apps by Mark Hamilton, Dryverless
51+
Collection of example applications written in Swift / Objective-C for iOS 9.x (developed under 9.2.1 SDK - will be migrated to 9.3 when released)
52+
######https://github.com/TheDarkCode/Example-Swift-Apps
53+
54+
##Support:
55+
56+
#####Send any questions or requests to: support@dryverless.com
57+
58+
## Contributing
59+
60+
- 1) Fork this repository!
61+
- 2) Create your feature branch: ```git checkout -b Your-New-Feature```
62+
- 3) Commit your changes: ```git commit -am 'Adding some super awesome update'```
63+
- 4) Push to the branch: ```git push origin Your-New-Feature```
64+
- 5) Submit a pull request!
65+
66+
## License
67+
Copyright (c) 2016 Mark Hamilton / dryverless (http://www.dryverless.com)
68+
69+
Permission is hereby granted, free of charge, to any person obtaining a copy
70+
of this software and associated documentation files (the "Software"), to deal
71+
in the Software without restriction, including without limitation the rights
72+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73+
copies of the Software, and to permit persons to whom the Software is
74+
furnished to do so, subject to the following conditions:
75+
76+
The above copyright notice and this permission notice shall be included in all
77+
copies or substantial portions of the Software.
78+
79+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
80+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
81+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
82+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
83+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
84+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
85+
SOFTWARE.

SwiftyLevenshtein.podspec

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Pod::Spec.new do |s|
2+
s.name = "SwiftyLevenshtein"
3+
s.version = "0.0.1"
4+
s.summary = "Levenshtein distance algorithm written in Swift 2.2. Both a slow and highly optimized version are included."
5+
s.homepage = "https://github.com/TheDarkCode/SwiftyLevenshtein"
6+
s.license = 'MIT'
7+
s.author = { "Mark Hamilton" => "mark@dryverless.com" }
8+
s.source = { :git => "https://github.com/TheDarkCode/SwiftyLevenshtein.git", :tag => s.version.to_s }
9+
s.social_media_url = 'https://twitter.com/dryverless'
10+
11+
s.platform = :ios, '8.0'
12+
s.requires_arc = true
13+
14+
s.source_files = 'Pod/Classes/**/*'
15+
16+
end

SwiftyLevenshtein.swift

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
//
2+
// SwiftyLevenshtein.swift
3+
// Levenshtein distance algorithm written in Swift 2.2. Both a slow and highly optimized version are included.
4+
//
5+
// Created by Mark Hamilton on 3/31/16.
6+
// Copyright © 2016 dryverless. (http://www.dryverless.com)
7+
//
8+
// Permission is hereby granted, free of charge, to any person obtaining a copy
9+
// of this software and associated documentation files (the "Software"), to deal
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be included in all
16+
// copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
// SOFTWARE.
25+
//
26+
27+
import Foundation
28+
29+
// Minimize 3
30+
public func min3(a: Int, b: Int, c: Int) -> Int {
31+
32+
return min( min(a, c), min(b, c))
33+
34+
}
35+
36+
// In case they ever let subscripts throw
37+
//public extension String {
38+
//
39+
// internal enum SubscriptError: ErrorType {
40+
//
41+
// case InvalidFirstChar
42+
//
43+
// case InvalidLastChar
44+
//
45+
// }
46+
//
47+
//
48+
// subscript(range: Range<Int>) throws -> String {
49+
//
50+
// guard let firstChar = startIndex.advancedBy(range.startIndex) else {
51+
//
52+
// throw SubscriptError.InvalidFirstChar
53+
// }
54+
//
55+
// guard let lastChar = startIndex.advancedBy(range.endIndex) else {
56+
//
57+
// throw SubscriptError.InvalidLastChar
58+
//
59+
// }
60+
//
61+
// return self[firstChar...<lastChar]
62+
//
63+
//
64+
// }
65+
//
66+
//}
67+
68+
public extension String {
69+
70+
subscript(index: Int) -> Character {
71+
72+
return self[startIndex.advancedBy(index)]
73+
74+
}
75+
76+
subscript(range: Range<Int>) -> String {
77+
78+
let char0 = startIndex.advancedBy(range.startIndex)
79+
80+
let charN = startIndex.advancedBy(range.endIndex)
81+
82+
return self[char0..<charN]
83+
84+
}
85+
86+
}
87+
88+
public struct Array2D {
89+
90+
var columns: Int
91+
var rows: Int
92+
var matrix: [Int]
93+
94+
95+
init(columns: Int, rows: Int) {
96+
97+
self.columns = columns
98+
99+
self.rows = rows
100+
101+
matrix = Array(count:columns*rows, repeatedValue:0)
102+
103+
}
104+
105+
subscript(column: Int, row: Int) -> Int {
106+
107+
get {
108+
109+
return matrix[columns * row + column]
110+
111+
}
112+
113+
set {
114+
115+
matrix[columns * row + column] = newValue
116+
117+
}
118+
119+
}
120+
121+
func columnCount() -> Int {
122+
123+
return self.columns
124+
125+
}
126+
127+
func rowCount() -> Int {
128+
129+
return self.rows
130+
131+
}
132+
}
133+
134+
/* Levenshtein Distance Algorithm
135+
* Calculates the minimum number of changes (distance) between two strings.
136+
*/
137+
138+
public func slowlevenshtein(sourceString: String, target targetString: String) -> Int {
139+
140+
let source = Array(sourceString.unicodeScalars)
141+
let target = Array(targetString.unicodeScalars)
142+
143+
let (sourceLength, targetLength) = (source.count, target.count)
144+
145+
var matrix = Array(count: targetLength + 1, repeatedValue: Array(count: sourceLength + 1, repeatedValue: 0))
146+
147+
for x in 1..<targetLength {
148+
149+
matrix[x][0] = matrix[x - 1][0] + 1
150+
151+
}
152+
153+
for y in 1..<sourceLength {
154+
155+
matrix[0][y] = matrix[0][y - 1] + 1
156+
157+
}
158+
159+
for x in 1..<(targetLength + 1) {
160+
161+
for y in 1..<(sourceLength + 1) {
162+
163+
let penalty = source[y - 1] == target[x - 1] ? 0 : 1
164+
165+
let (deletions, insertions, substitutions) = (matrix[x - 1][y] + 1, matrix[x][y - 1] + 1, matrix[x - 1][y - 1])
166+
167+
matrix[x][y] = min3(deletions, b: insertions, c: substitutions + penalty)
168+
169+
}
170+
171+
}
172+
173+
return matrix[targetLength][sourceLength]
174+
175+
}
176+
177+
public func levenshtein(sourceString: String, target targetString: String) -> Int {
178+
179+
let source = Array(sourceString.unicodeScalars)
180+
let target = Array(targetString.unicodeScalars)
181+
182+
let (sourceLength, targetLength) = (source.count, target.count)
183+
184+
var distance = Array2D(columns: sourceLength + 1, rows: targetLength + 1)
185+
186+
for x in 1...sourceLength {
187+
188+
distance[x, 0] = x
189+
190+
}
191+
192+
for y in 1...targetLength {
193+
194+
distance[0, y] = y
195+
196+
}
197+
198+
for x in 1...sourceLength {
199+
200+
for y in 1...targetLength {
201+
202+
if source[x - 1] == target[y - 1] {
203+
204+
// no difference
205+
distance[x, y] = distance[x - 1, y - 1]
206+
207+
} else {
208+
209+
distance[x, y] = min3(
210+
211+
// deletions
212+
distance[x - 1, y] + 1,
213+
// insertions
214+
b: distance[x, y - 1] + 1,
215+
// substitutions
216+
c: distance[x - 1, y - 1] + 1
217+
218+
)
219+
220+
}
221+
222+
}
223+
224+
}
225+
226+
return distance[source.count, target.count]
227+
228+
}
229+
230+
public extension String {
231+
232+
func getSlowLevenshtein(target: String) -> Int {
233+
234+
return slowlevenshtein(self, target: target)
235+
236+
}
237+
238+
func getLevenshtein(target: String) -> Int {
239+
240+
return levenshtein(self, target: target)
241+
242+
}
243+
244+
}

0 commit comments

Comments
 (0)