From 8bf8fe012b4bb052d46084e1e331495a9da26614 Mon Sep 17 00:00:00 2001 From: Mark Hamilton Date: Thu, 31 Mar 2016 05:12:47 -0700 Subject: [PATCH] Release 0.0.1 --- .gitignore | 33 +++ LICENSE | 4 +- Pod/Assets/.gitkeep | 1 + Pod/Classes/.gitkeep | 1 + Pod/{ => Classes}/SwiftyLevenshtein.swift | 0 README.md | 83 ++++++++ SwiftyLevenshtein.podspec | 16 ++ SwiftyLevenshtein.swift | 244 ++++++++++++++++++++++ 8 files changed, 379 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 Pod/Assets/.gitkeep create mode 100644 Pod/Classes/.gitkeep rename Pod/{ => Classes}/SwiftyLevenshtein.swift (100%) create mode 100644 SwiftyLevenshtein.podspec create mode 100644 SwiftyLevenshtein.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8615121 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control +# +# Pods/ + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build diff --git a/LICENSE b/LICENSE index 646df03..6843b82 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,4 @@ -The MIT License (MIT) - -Copyright (c) 2016 Mark Hamilton +Copyright (c) 2016 Mark Hamilton / dryverless (http://www.dryverless.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Pod/Assets/.gitkeep b/Pod/Assets/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Pod/Assets/.gitkeep @@ -0,0 +1 @@ + diff --git a/Pod/Classes/.gitkeep b/Pod/Classes/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Pod/Classes/.gitkeep @@ -0,0 +1 @@ + diff --git a/Pod/SwiftyLevenshtein.swift b/Pod/Classes/SwiftyLevenshtein.swift similarity index 100% rename from Pod/SwiftyLevenshtein.swift rename to Pod/Classes/SwiftyLevenshtein.swift diff --git a/README.md b/README.md index 7f75f1a..0699cbf 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,85 @@ # SwiftyLevenshtein Levenshtein distance algorithm written in Swift 2.2. Both a slow and highly optimized version are included. + +##Usage + +```swift +var source_string = "x men" +var target_string = "x mn" + + +source_string.getLevenshtein(target_string) // 1 +target_string.getLevenshtein(source_string) // 1 + +//source_string.getSlowLevenshtein(target_string) // 1 +//target_string.getSlowLevenshtein(source_string) // 1 + +//levenshtein(source_string, target: target_string) // 1 + +//slowlevenshtein(source_string, target: target_string) // 1 +``` + +##CocoaPods + +[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: + +```bash +$ gem install cocoapods +``` + +> CocoaPods 0.39.0+ is required to build SwiftyLevenshtein 0.0.1+. + +To integrate SwiftyLevenshtein into your Xcode project using CocoaPods, specify it in your `Podfile`: + +```ruby +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' +use_frameworks! + +pod 'SwiftyLevenshtein', '~> 0.0.1' +``` + +Then, run the following command: + +```bash +$ pod install +``` + +##Related Projects: + +###Example Swift Apps by Mark Hamilton, Dryverless +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) +######https://github.com/TheDarkCode/Example-Swift-Apps + +##Support: + +#####Send any questions or requests to: support@dryverless.com + +## Contributing + + - 1) Fork this repository! + - 2) Create your feature branch: ```git checkout -b Your-New-Feature``` + - 3) Commit your changes: ```git commit -am 'Adding some super awesome update'``` + - 4) Push to the branch: ```git push origin Your-New-Feature``` + - 5) Submit a pull request! + +## License +Copyright (c) 2016 Mark Hamilton / dryverless (http://www.dryverless.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/SwiftyLevenshtein.podspec b/SwiftyLevenshtein.podspec new file mode 100644 index 0000000..0312717 --- /dev/null +++ b/SwiftyLevenshtein.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| + s.name = "SwiftyLevenshtein" + s.version = "0.0.1" + s.summary = "Levenshtein distance algorithm written in Swift 2.2. Both a slow and highly optimized version are included." + s.homepage = "https://github.com/TheDarkCode/SwiftyLevenshtein" + s.license = 'MIT' + s.author = { "Mark Hamilton" => "mark@dryverless.com" } + s.source = { :git => "https://github.com/TheDarkCode/SwiftyLevenshtein.git", :tag => s.version.to_s } + s.social_media_url = 'https://twitter.com/dryverless' + + s.platform = :ios, '8.0' + s.requires_arc = true + + s.source_files = 'Pod/Classes/**/*' + +end diff --git a/SwiftyLevenshtein.swift b/SwiftyLevenshtein.swift new file mode 100644 index 0000000..a4c48db --- /dev/null +++ b/SwiftyLevenshtein.swift @@ -0,0 +1,244 @@ +// +// SwiftyLevenshtein.swift +// Levenshtein distance algorithm written in Swift 2.2. Both a slow and highly optimized version are included. +// +// Created by Mark Hamilton on 3/31/16. +// Copyright © 2016 dryverless. (http://www.dryverless.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation + +// Minimize 3 +public func min3(a: Int, b: Int, c: Int) -> Int { + + return min( min(a, c), min(b, c)) + +} + +// In case they ever let subscripts throw +//public extension String { +// +// internal enum SubscriptError: ErrorType { +// +// case InvalidFirstChar +// +// case InvalidLastChar +// +// } +// +// +// subscript(range: Range) throws -> String { +// +// guard let firstChar = startIndex.advancedBy(range.startIndex) else { +// +// throw SubscriptError.InvalidFirstChar +// } +// +// guard let lastChar = startIndex.advancedBy(range.endIndex) else { +// +// throw SubscriptError.InvalidLastChar +// +// } +// +// return self[firstChar... Character { + + return self[startIndex.advancedBy(index)] + + } + + subscript(range: Range) -> String { + + let char0 = startIndex.advancedBy(range.startIndex) + + let charN = startIndex.advancedBy(range.endIndex) + + return self[char0.. Int { + + get { + + return matrix[columns * row + column] + + } + + set { + + matrix[columns * row + column] = newValue + + } + + } + + func columnCount() -> Int { + + return self.columns + + } + + func rowCount() -> Int { + + return self.rows + + } +} + +/* Levenshtein Distance Algorithm + * Calculates the minimum number of changes (distance) between two strings. + */ + +public func slowlevenshtein(sourceString: String, target targetString: String) -> Int { + + let source = Array(sourceString.unicodeScalars) + let target = Array(targetString.unicodeScalars) + + let (sourceLength, targetLength) = (source.count, target.count) + + var matrix = Array(count: targetLength + 1, repeatedValue: Array(count: sourceLength + 1, repeatedValue: 0)) + + for x in 1.. Int { + + let source = Array(sourceString.unicodeScalars) + let target = Array(targetString.unicodeScalars) + + let (sourceLength, targetLength) = (source.count, target.count) + + var distance = Array2D(columns: sourceLength + 1, rows: targetLength + 1) + + for x in 1...sourceLength { + + distance[x, 0] = x + + } + + for y in 1...targetLength { + + distance[0, y] = y + + } + + for x in 1...sourceLength { + + for y in 1...targetLength { + + if source[x - 1] == target[y - 1] { + + // no difference + distance[x, y] = distance[x - 1, y - 1] + + } else { + + distance[x, y] = min3( + + // deletions + distance[x - 1, y] + 1, + // insertions + b: distance[x, y - 1] + 1, + // substitutions + c: distance[x - 1, y - 1] + 1 + + ) + + } + + } + + } + + return distance[source.count, target.count] + +} + +public extension String { + + func getSlowLevenshtein(target: String) -> Int { + + return slowlevenshtein(self, target: target) + + } + + func getLevenshtein(target: String) -> Int { + + return levenshtein(self, target: target) + + } + +}