extension String {
subscript(index:Int) -> Character {
if index < 0 {
return self[advance(self.endIndex, index)]
}
return self[advance(self.startIndex, index)]
}
func substring(from:Int, to: Int = -1) -> String {
return self[Range<Int>(start: from, end: to)]
}
func substring(from:Int, length: Int) -> String {
return self[Range<Int>(start: from, end: from + length)]
}
func substring(range:NSRange) -> String {
return self[Range<Int>(start: range.location, end: range.location + range.length)]
}
subscript(range:Range<Int>) -> String {
if range.startIndex >= self.length() {
return String()
}
let start = advance(self.startIndex, min(self.length(), range.startIndex))
if range.endIndex < 0 {
return self[start..<self.endIndex]
}
let end = advance(self.startIndex, min(self.length(), range.endIndex))
return self[start..<end]
}
func allIndexesOf(string: String) -> [Int] {
var res:[Int] = []
var substr = self.substring(0)
while let index = substr.firstIndexOf(string) {
res.append(index + (self.length() - substr.length()))
substr = substr.substring(index + string.length())
}
return res
}
func firstIndexOf(string: String) -> Int? {
if let range = self.rangeOfString(string,
options: NSStringCompareOptions.LiteralSearch,
range: self.startIndex..<self.endIndex,
locale: NSLocale.autoupdatingCurrentLocale())
{
return self.unwrapIndex(range.startIndex)
}
return nil
}
func firstIndexOf(charset: NSCharacterSet) -> Int? {
return self.componentsSeparatedByCharactersInSet(charset).first?.length()
}
func lastIndexOf(charset: NSCharacterSet) -> Int? {
return self.componentsSeparatedByCharactersInSet(charset).last?.length()
}
func contains(string: String) -> Bool {
return self.firstIndexOf(string) != nil
}
func contains(charset: NSCharacterSet) -> Bool {
return count(self.componentsSeparatedByCharactersInSet(charset)) > 1
}
func lastIndexOf(string: String) -> Int? {
if let range = self.rangeOfString(string,
options: NSStringCompareOptions.BackwardsSearch | NSStringCompareOptions.LiteralSearch,
range: self.startIndex..<self.endIndex,
locale: NSLocale.autoupdatingCurrentLocale())
{
return self.unwrapIndex(range.startIndex)
}
return nil
}
func startsWith(string: String) -> Bool {
return self.firstIndexOf(string) == 0
}
func startsWith(charset: NSCharacterSet) -> Bool {
if self.length() == 0 {
return false
}
return self.substring(0, to: 1).stringByTrimmingCharactersInSet(charset).length() == 0
}
func endsWith(charset: NSCharacterSet) -> Bool {
if self.length() == 0 {
return false
}
return self.substring(self.length() - 1, to: -1).stringByTrimmingCharactersInSet(charset).length() == 0
}
func endsWith(string: String) -> Bool {
return self.lastIndexOf(string) == self.length() - string.length()
}
func unwrapIndex(index: String.Index) -> Int {
var cursor = self.startIndex
var res:Int = 0
while cursor != index {
cursor = advance(cursor, 1)
res += 1
}
return res
}
func wrapIndex(index: Int) -> String.Index {
var cursor = self.startIndex
return advance(cursor, index)
}
func length() -> Int {
return count(self)
}
// modified from https://gist.github.com/kyro38/50102a47937e9896e4f4
func levenshteinDistance(toString: String) -> Int {
class Array2D {
var cols:Int, rows:Int
var matrix: [Int]
init(cols:Int, rows:Int) {
self.cols = cols
self.rows = rows
matrix = Array(count:cols*rows, repeatedValue:0)
}
subscript(col:Int, row:Int) -> Int {
get {
return matrix[cols * row + col]
}
set {
matrix[cols*row+col] = newValue
}
}
func colCount() -> Int {
return self.cols
}
func rowCount() -> Int {
return self.rows
}
}
let a = Array(self.utf16)
let b = Array(toString.utf16)
var dist = Array2D(cols: a.count + 1, rows: b.count + 1)
for i in 1...a.count {
dist[i, 0] = i
}
for j in 1...b.count {
dist[0, j] = j
}
for i in 1...a.count {
for j in 1...b.count {
if a[i-1] == b[j-1] {
dist[i, j] = dist[i-1, j-1] // noop
} else {
dist[i, j] = min(
dist[i-1, j] + 1, // deletion
dist[i, j-1] + 1, // insertion
dist[i-1, j-1] + 1 // substitution
)
}
}
}
return dist[a.count, b.count]
}
func matchRegex(pattern: Regex) -> Bool {
let range: NSRange = NSMakeRange(0, count(self))
if pattern.regex != nil {
let matches: [AnyObject] = pattern.regex!.matchesInString(self, options: pattern.matchingOptions, range: range)
return matches.count > 0
}
return false
}
func match(patternString: String) -> Bool {
return self.matchRegex(Regex(pattern: patternString))
}
func replaceRegex(pattern: Regex, template: String) -> String {
if self.matchRegex(pattern) {
let range: NSRange = NSMakeRange(0, count(self))
if pattern.regex != nil {
return pattern.regex!.stringByReplacingMatchesInString(self, options: pattern.matchingOptions, range: range, withTemplate: template)
}
}
return self
}
func replace(pattern: String, template: String) -> String {
return self.replaceRegex(Regex(pattern: pattern), template: template)
}
func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
let utf16start = self.utf16.startIndex
if let from = String.Index(self.utf16.startIndex + nsRange.location, within: self),
let to = String.Index(self.utf16.startIndex + nsRange.location + nsRange.length, within: self) {
return from ..< to
}
return nil
}
}