From 2ecdbfff937410bea7c9f52ee79bd18457ea2689 Mon Sep 17 00:00:00 2001 From: Solomiya Nazarkevych Date: Tue, 14 Mar 2017 11:11:50 +0200 Subject: [PATCH 1/2] Converted to Swift 3. --- Pod/Classes/String+HTML.swift | 28 +++-- Pod/Classes/StringExtensions.swift | 191 ++++++++++++----------------- 2 files changed, 91 insertions(+), 128 deletions(-) diff --git a/Pod/Classes/String+HTML.swift b/Pod/Classes/String+HTML.swift index 1895b55..e81539f 100644 --- a/Pod/Classes/String+HTML.swift +++ b/Pod/Classes/String+HTML.swift @@ -270,7 +270,7 @@ public extension String { // decodeNumeric("20ac", 16) --> "€" private func decodeNumeric(string : String, base : Int32) -> Character? { let code = UInt32(strtoul(string, nil, base)) - return Character(UnicodeScalar(code)) + return Character(UnicodeScalar(code)!) } // Decode the HTML character entity to the corresponding @@ -281,9 +281,11 @@ public extension String { // decode("&foo;") --> nil private func decode(entity : String) -> Character? { if entity.hasPrefix("&#x") || entity.hasPrefix("&#X"){ - return decodeNumeric(entity.substringFromIndex(entity.startIndex.advancedBy(3)), base: 16) + let index = entity.index(entity.startIndex, offsetBy: 3) + return decodeNumeric(string: entity.substring(from: index), base: 16) } else if entity.hasPrefix("&#") { - return decodeNumeric(entity.substringFromIndex(entity.startIndex.advancedBy(2)), base: 10) + let index = entity.index(entity.startIndex, offsetBy: 2) + return decodeNumeric(string: entity.substring(from: index), base: 10) } else { return HTMLEntities.characterEntities[entity] } @@ -298,21 +300,21 @@ public extension String { var position = startIndex // Find the next '&' and copy the characters preceding it to `result`: - while let ampRange = self.rangeOfString("&", range: position ..< endIndex) { - result.appendContentsOf(self[position ..< ampRange.startIndex]) - position = ampRange.startIndex + while let ampRange = self.range(of: "&", range: position ..< endIndex) { + result.append(self[position ..< ampRange.lowerBound]) + position = ampRange.lowerBound // Find the next ';' and copy everything from '&' to ';' into `entity` - if let semiRange = self.rangeOfString(";", range: position ..< endIndex) { - let entity = self[position ..< semiRange.endIndex] - position = semiRange.endIndex + if let semiRange = self.range(of: ";", range: position ..< endIndex) { + let entity = self[position ..< semiRange.upperBound] + position = semiRange.upperBound - if let decoded = decode(entity) { + if let decoded = decode(entity: entity) { // Replace by decoded character: result.append(decoded) } else { // Invalid entity, copy verbatim: - result.appendContentsOf(entity) + result.append(entity) } } else { // No matching ';'. @@ -320,7 +322,7 @@ public extension String { } } // Copy remaining characters to `result`: - result.appendContentsOf(self[position ..< endIndex]) + result.append(self[position ..< endIndex]) return result } -} \ No newline at end of file +} diff --git a/Pod/Classes/StringExtensions.swift b/Pod/Classes/StringExtensions.swift index 218d426..c981a87 100644 --- a/Pod/Classes/StringExtensions.swift +++ b/Pod/Classes/StringExtensions.swift @@ -16,74 +16,75 @@ public extension String { /// - returns: The string between the two bookends, or nil if the bookends cannot be found, the bookends are the same or appear contiguously. func between(left: String, _ right: String) -> String? { guard - let leftRange = rangeOfString(left), rightRange = rangeOfString(right, options: .BackwardsSearch) - where left != right && leftRange.endIndex != rightRange.startIndex + let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards), left != right && leftRange.upperBound != rightRange.lowerBound else { return nil } - return self[leftRange.endIndex...rightRange.startIndex.predecessor()] + let rightRangeAgain = range(of: right, options: .backwards) + return self[leftRange.upperBound...right.index(before: (rightRangeAgain?.lowerBound)!)] } // https://gist.github.com/stevenschobert/540dd33e828461916c11 func camelize() -> String { let source = clean(with: " ", allOf: "-", "_") + let index = source.index(source.startIndex, offsetBy: 1) if source.characters.contains(" ") { - let first = source.substringToIndex(source.startIndex.advancedBy(1)) - let cammel = NSString(format: "%@", (source as NSString).capitalizedString.stringByReplacingOccurrencesOfString(" ", withString: "", options: [], range: nil)) as String + let first = source.substring(to: index) + let cammel = NSString(format: "%@", (source.capitalized as NSString).replacingOccurrences(of: " ", with: "")) as String let rest = String(cammel.characters.dropFirst()) return "\(first)\(rest)" } else { - let first = (source as NSString).lowercaseString.substringToIndex(source.startIndex.advancedBy(1)) + let first = (source as NSString).lowercased.substring(to: index) let rest = String(source.characters.dropFirst()) return "\(first)\(rest)" } } func capitalize() -> String { - return capitalizedString + return capitalized } func contains(substring: String) -> Bool { - return rangeOfString(substring) != nil + return range(of: substring) != nil } func chompLeft(prefix: String) -> String { - if let prefixRange = rangeOfString(prefix) { - if prefixRange.endIndex >= endIndex { - return self[startIndex..= endIndex { + return self[startIndex.. String { - if let suffixRange = rangeOfString(suffix, options: .BackwardsSearch) { - if suffixRange.endIndex >= endIndex { - return self[startIndex..= endIndex { + return self[startIndex.. String { - let components = componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).filter { !$0.isEmpty } - return components.joinWithSeparator(" ") + let componentsOf = components(separatedBy: NSCharacterSet.whitespacesAndNewlines).filter { !$0.isEmpty } + return componentsOf.joined(separator: " ") } func clean(with with: String, allOf: String...) -> String { var string = self for target in allOf { - string = string.stringByReplacingOccurrencesOfString(target, withString: with) + string = string.replacingOccurrences(of: target, with: with) } return string } func count(substring: String) -> Int { - return componentsSeparatedByString(substring).count-1 + return components(separatedBy: substring).count-1 } func endsWith(suffix: String) -> Bool { @@ -91,7 +92,7 @@ public extension String { } func ensureLeft(prefix: String) -> String { - if startsWith(prefix) { + if startsWith(prefix: prefix) { return self } else { return "\(prefix)\(self)" @@ -99,7 +100,7 @@ public extension String { } func ensureRight(suffix: String) -> String { - if endsWith(suffix) { + if endsWith(suffix: suffix) { return self } else { return "\(self)\(suffix)" @@ -107,22 +108,30 @@ public extension String { } func indexOf(substring: String) -> Int? { - if let range = rangeOfString(substring) { - return startIndex.distanceTo(range.startIndex) + if let range = range(of: substring) { + return distance(from: startIndex, to: range.lowerBound) } return nil } func initials() -> String { - let words = self.componentsSeparatedByString(" ") + let words = self.components(separatedBy: " ") return words.reduce(""){$0 + $1[0...0]} } func initialsFirstAndLast() -> String { - let words = self.componentsSeparatedByString(" ") + let words = self.components(separatedBy: " ") return words.reduce("") { ($0 == "" ? "" : $0[0...0]) + $1[0...0]} } + subscript (r: CountableClosedRange) -> String { + get { + let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound) + let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound) + return self[startIndex...endIndex] + } + } + func isAlpha() -> Bool { for chr in characters { if (!(chr >= "a" && chr <= "z") && !(chr >= "A" && chr <= "Z") ) { @@ -133,31 +142,31 @@ public extension String { } func isAlphaNumeric() -> Bool { - let alphaNumeric = NSCharacterSet.alphanumericCharacterSet() - return componentsSeparatedByCharactersInSet(alphaNumeric).joinWithSeparator("").length == 0 + let alphaNumeric = NSCharacterSet.alphanumerics + return components(separatedBy: alphaNumeric).joined(separator: "").length == 0 } func isEmpty() -> Bool { - return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).length == 0 + return self.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines).length == 0 } func isNumeric() -> Bool { - if let _ = defaultNumberFormatter().numberFromString(self) { + if let _ = NumberFormatter().number(from: self) { return true } return false } - func join(elements: S) -> String { - return elements.map{String($0)}.joinWithSeparator(self) + func join(elements: S) -> String { + return elements.map{String(describing: $0)}.joined(separator: self) } func latinize() -> String { - return self.stringByFoldingWithOptions(.DiacriticInsensitiveSearch, locale: NSLocale.currentLocale()) + return self.folding(options: .diacriticInsensitive, locale: Locale.current) } func lines() -> [String] { - return self.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) + return self.components(separatedBy: NSCharacterSet.newlines) } var length: Int { @@ -167,24 +176,24 @@ public extension String { } func pad(n: Int, _ string: String = " ") -> String { - return "".join([string.times(n), self, string.times(n)]) + return "".join(elements: [string.times(n: n), self, string.times(n: n)]) } func padLeft(n: Int, _ string: String = " ") -> String { - return "".join([string.times(n), self]) + return "".join(elements: [string.times(n: n), self]) } func padRight(n: Int, _ string: String = " ") -> String { - return "".join([self, string.times(n)]) + return "".join(elements: [self, string.times(n: n)]) } func slugify(withSeparator separator: Character = "-") -> String { - let slugCharacterSet = NSCharacterSet(charactersInString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\(separator)") + let slugCharacterSet = NSCharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\(separator)") return latinize() - .lowercaseString - .componentsSeparatedByCharactersInSet(slugCharacterSet.invertedSet) + .lowercased() + .components(separatedBy: slugCharacterSet.inverted) .filter { $0 != "" } - .joinWithSeparator(String(separator)) + .joined(separator: String(separator)) } func split(separator: Character) -> [String] { @@ -196,11 +205,11 @@ public extension String { } func stripPunctuation() -> String { - return componentsSeparatedByCharactersInSet(.punctuationCharacterSet()) - .joinWithSeparator("") - .componentsSeparatedByString(" ") + return components(separatedBy: .punctuationCharacters) + .joined(separator: "") + .components(separatedBy: " ") .filter { $0 != "" } - .joinWithSeparator(" ") + .joined(separator: " ") } func times(n: Int) -> String { @@ -208,30 +217,30 @@ public extension String { } func toFloat() -> Float? { - if let number = defaultNumberFormatter().numberFromString(self) { + if let number = NumberFormatter().number(from: self) { return number.floatValue } return nil } func toInt() -> Int? { - if let number = defaultNumberFormatter().numberFromString(self) { - return number.integerValue + if let number = NumberFormatter().number(from: self) { + return number.intValue } return nil } - func toDouble(locale: NSLocale = NSLocale.systemLocale()) -> Double? { - let nf = localeNumberFormatter(locale) - - if let number = nf.numberFromString(self) { + func toDouble(locale: Locale = Locale.current) -> Double? { + let nf = NumberFormatter() + nf.locale = locale as Locale! + if let number = nf.number(from: self) { return number.doubleValue } return nil } func toBool() -> Bool? { - let trimmed = self.trimmed().lowercaseString + let trimmed = self.trimmed().lowercased() if trimmed == "true" || trimmed == "false" { return (trimmed as NSString).boolValue } @@ -239,99 +248,51 @@ public extension String { } func toDate(format: String = "yyyy-MM-dd") -> NSDate? { - return dateFormatter(format).dateFromString(self) + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = format + return dateFormatter.date(from: self) as NSDate? } func toDateTime(format: String = "yyyy-MM-dd HH:mm:ss") -> NSDate? { - return toDate(format) + return toDate(format: format) } func trimmedLeft() -> String { - if let range = rangeOfCharacterFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet().invertedSet) { - return self[range.startIndex.. String { - if let range = rangeOfCharacterFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet().invertedSet, options: NSStringCompareOptions.BackwardsSearch) { - return self[startIndex.. String { - return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + return self.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines) } subscript(r: Range) -> String { get { - let startIndex = self.startIndex.advancedBy(r.startIndex) - let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex) + let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound) + let endIndex = self.index(self.startIndex, offsetBy: r.upperBound - r.lowerBound) return self[startIndex.. String { - let start = self.startIndex.advancedBy(startIndex) - let end = self.startIndex.advancedBy(startIndex + length) + let start = self.index(self.startIndex, offsetBy: startIndex) + let end = self.index(self.startIndex, offsetBy:startIndex + length) return self[start.. Character { get { - let index = self.startIndex.advancedBy(i) + let index = self.index(startIndex, offsetBy: i) return self[index] } } } - -private enum ThreadLocalIdentifier { - case DateFormatter(String) - - case DefaultNumberFormatter - case LocaleNumberFormatter(NSLocale) - - var objcDictKey: String { - switch self { - case .DateFormatter(let format): - return "SS\(self)\(format)" - case .LocaleNumberFormatter(let l): - return "SS\(self)\(l.localeIdentifier)" - default: - return "SS\(self)" - } - } -} - -private func threadLocalInstance(identifier: ThreadLocalIdentifier, @autoclosure initialValue: () -> T) -> T { - let storage = NSThread.currentThread().threadDictionary - let k = identifier.objcDictKey - - let instance: T = storage[k] as? T ?? initialValue() - if storage[k] == nil { - storage[k] = instance - } - - return instance -} - -private func dateFormatter(format: String) -> NSDateFormatter { - return threadLocalInstance(.DateFormatter(format), initialValue: { - let df = NSDateFormatter() - df.dateFormat = format - return df - }()) -} - -private func defaultNumberFormatter() -> NSNumberFormatter { - return threadLocalInstance(.DefaultNumberFormatter, initialValue: NSNumberFormatter()) -} - -private func localeNumberFormatter(locale: NSLocale) -> NSNumberFormatter { - return threadLocalInstance(.LocaleNumberFormatter(locale), initialValue: { - let nf = NSNumberFormatter() - nf.locale = locale - return nf - }()) -} From 1d6e4f6c4789a2b0df656a1bac32dec4b9876fcb Mon Sep 17 00:00:00 2001 From: Solomiya Nazarkevych Date: Thu, 23 Mar 2017 10:40:29 +0200 Subject: [PATCH 2/2] Updated Podfile. --- Example/Podfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index f013c53..342c639 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -1,11 +1,11 @@ source 'https://github.com/CocoaPods/Specs.git' use_frameworks! -target 'SwiftString_Example', :exclusive => true do +target 'SwiftString_Example' do pod 'SwiftString', :path => '../' end -target 'SwiftString_Tests', :exclusive => true do +target 'SwiftString_Tests' do pod 'SwiftString', :path => '../' pod 'SwiftHamcrest' end