0001    // String.swift
0002    //
0003    // The MIT License (MIT)
0004    //
0005    // Copyright (c) 2015 Zewo
0006    //
0007    // Permission is hereby granted, free of charge, to any person obtaining a copy
0008    // of this software and associated documentation files (the "Software"), to deal
0009    // in the Software without restriction, including without limitation the rights
0010    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0011    // copies of the Software, and to permit persons to whom the Software is
0012    // furnished to do so, subject to the following conditions:
0013    //
0014    // The above copyright notice and this permission notice shall be included in all
0015    // copies or substantial portions of the Software.
0016    //
0017    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0018    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0019    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0020    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0021    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0022    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0023    // SOFTWARE.
0024    
0025    import System
0026    
0027    extension String {
0028        public static func bufferWithSize
String.swift:33
        var buffer = String.bufferWithSize(length + 1)
(size: Int) -> [Int8] { 0029 return [Int8](count: size, repeatedValue: 0) 0030 } 0031 0032 public init?(pointer: UnsafePointer<Int8>, length: Int) { 0033 var buffer = String.bufferWithSize(length + 1) 0034 strncpy(&buffer, pointer, length) 0035 0036 guard let string = String.fromCString(buffer) else { 0037 return nil 0038 } 0039 0040 self.init(string) 0041 } 0042 0043 subscript (i: Int) -> Character? { 0044 guard i >= 0 && i < characters.count else { return nil } 0045 return self[startIndex.advancedBy(i)] 0046 } 0047 0048 subscript (i: Range<Int>) -> String? { 0049 let start = i.startIndex, end = i.endIndex 0050 guard start >= 0 && start <= characters.count && end >= 0 && end <= characters.count && start < end else { return nil } 0051 return self[startIndex.advancedBy(start) ..< startIndex.advancedBy(end)] 0052 } 0053 0054 public func split(separator: Character, maxSplit: Int = .max, allowEmptySlices: Bool = false) -> [String] { 0055 return characters.split(separator, maxSplit: maxSplit, allowEmptySlices: allowEmptySlices).map(String.init) 0056 } 0057 0058 public func trim() -> String { 0059 return trim(CharacterSet.whitespaceAndNewline) 0060 } 0061 0062 public func trim
String.swift:59
        return trim(CharacterSet.whitespaceAndNewline)
(characters: CharacterSet) -> String { 0063 let string = trimLeft(characters) 0064 return string.trimRight(characters) 0065 } 0066 0067 public func trimLeft
String.swift:63
        let string = trimLeft(characters)
(characterSet: CharacterSet) -> String { 0068 var start = characters.count 0069 0070 for (index, character) in characters.enumerate() { 0071 if !characterSet.contains(character) { 0072 start = index 0073 break 0074 } 0075 } 0076 0077 return self[startIndex.advancedBy(start) ..< endIndex] 0078 } 0079 0080 public func trimRight
String.swift:64
        return string.trimRight(characters)
(characterSet: CharacterSet) -> String { 0081 var end = characters.count 0082 0083 for (index, character) in characters.reverse().enumerate() { 0084 if !characterSet.contains(character) { 0085 end = index 0086 break 0087 } 0088 } 0089 0090 return self[startIndex ..< startIndex.advancedBy(characters.count - end)] 0091 } 0092 0093 public func indexOf
String.swift:98
		return indexOf(string) != nil
(string: String) -> String.CharacterView.Index? { 0094 return characters.indexOf(string.characters) 0095 } 0096 0097 public func contains(string: String) -> Bool { 0098 return indexOf(string) != nil 0099 } 0100 0101 public func splitBy(separator: String) -> [String] { 0102 let separatorChars = separator.characters 0103 guard var index = characters.indexOf(separatorChars) else { 0104 return [self] 0105 } 0106 let separatorCount = separatorChars.count 0107 var start = characters.startIndex 0108 var array: [String] = [] 0109 while true { 0110 let distance = characters.startIndex.distanceTo(index) 0111 let trange = start ..< characters.startIndex.advancedBy(distance + characters.startIndex.distanceTo(start)) 0112 array.append(String(characters[trange])) 0113 start = start.advancedBy(distance + separatorCount) 0114 let substr = characters.suffixFrom(start) 0115 if let _index = substr.indexOf(separatorChars) { 0116 index = _index 0117 } else { 0118 break 0119 } 0120 } 0121 array.append(String(characters[start ..< characters.endIndex])) 0122 return array 0123 } 0124 0125 public mutating func replace(string: String, with: String) { 0126 let strChars = string.characters 0127 let strCount = strChars.count 0128 while true { 0129 guard let index = characters.indexOf(strChars) else { break } 0130 replaceRange(index ..< index.advancedBy(strCount), with: with) 0131 } 0132 } 0133 0134 } 0135 0136 extension String.CharacterView { 0137 0138 func indexOf
String.swift:94
		return characters.indexOf(string.characters)
String.swift:103
		guard var index = characters.indexOf(separatorChars) else {
String.swift:115
			if let _index = substr.indexOf(separatorChars) {
String.swift:129
			guard let index = characters.indexOf(strChars) else { break }
(sequence: String.CharacterView) -> String.CharacterView.Index? { 0139 guard let firstChar = sequence.first else { 0140 return nil 0141 } 0142 let seqString = String(sequence) 0143 for (i, char) in enumerate() { 0144 guard char == firstChar else { continue } 0145 let start = startIndex.advancedBy(i) 0146 let end = startIndex.advancedBy(i+sequence.count) 0147 if String(self[start ..< end]) == seqString { 0148 return start 0149 } 0150 } 0151 return nil 0152 } 0153 0154 } 0155 0156 public struct CharacterSet
String.swift:59
        return trim(CharacterSet.whitespaceAndNewline)
String.swift:62
    public func trim(characters: CharacterSet) -> String {
String.swift:67
    public func trimLeft(characterSet: CharacterSet) -> String {
String.swift:80
    public func trimRight(characterSet: CharacterSet) -> String {
String.swift:157
	public static var whitespaceAndNewline: CharacterSet {
String.swift:161
	public static var digits: CharacterSet {
String.swift:169
		return CharacterSet(characters: characters, inverted: !isInverted)
String.swift:168
	public var inverted: CharacterSet {
: ArrayLiteralConvertible { 0157 public static var whitespaceAndNewline
String.swift:59
        return trim(CharacterSet.whitespaceAndNewline)
: CharacterSet { 0158 return [" ", "\t", "\r", "\n"] 0159 } 0160 0161 public static var digits: CharacterSet { 0162 return ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] 0163 } 0164 0165 private let characters
String.swift:169
		return CharacterSet(characters: characters, inverted: !isInverted)
String.swift:173
		self.characters = characters
String.swift:182
		let contains = characters.contains(character)
: Set<Character> 0166 private let isInverted
String.swift:169
		return CharacterSet(characters: characters, inverted: !isInverted)
String.swift:174
		self.isInverted = inverted
String.swift:183
		return isInverted ? !contains : contains
: Bool 0167 0168 public var inverted: CharacterSet { 0169 return CharacterSet(characters: characters, inverted: !isInverted) 0170 } 0171 0172 public init
String.swift:169
		return CharacterSet(characters: characters, inverted: !isInverted)
String.swift:178
		self.init(characters: Set(elements))
(characters: Set<Character>, inverted: Bool = false) { 0173 self.characters = characters 0174 self.isInverted = inverted 0175 } 0176 0177 public init(arrayLiteral elements: Character...) { 0178 self.init(characters: Set(elements)) 0179 } 0180 0181 public func contains
String.swift:71
            if !characterSet.contains(character) {
String.swift:84
            if !characterSet.contains(character) {
(character: Character) -> Bool { 0182 let contains = characters.contains(character) 0183 return isInverted ? !contains : contains 0184 } 0185 } 0186 0187 extension String { 0188 public func startsWith(prefix: String) -> Bool { 0189 return prefix == String(self.characters.prefix(prefix.characters.count)) 0190 } 0191 0192 public func endsWith
String.swift:220
        precondition(!endsWith("/") && characters.count > 1)
String.swift:269
        if stripTrailing && result.endsWith("/") {
(suffix: String) -> Bool { 0193 return suffix == String(self.characters.suffix(suffix.characters.count)) 0194 } 0195 0196 public var dropLastPathComponent: String { 0197 let fixedSelf = fixSlashes() 0198 0199 if fixedSelf == "/" { 0200 return fixedSelf 0201 } 0202 0203 switch fixedSelf.startOfLastPathComponent { 0204 0205 // relative path, single component 0206 case fixedSelf.startIndex: 0207 return "" 0208 0209 // absolute path, single component 0210 case fixedSelf.startIndex.successor(): 0211 return "/" 0212 0213 // all common cases 0214 case let startOfLast: 0215 return String(fixedSelf.characters.prefixUpTo(startOfLast.predecessor())) 0216 } 0217 } 0218 0219 var startOfLastPathComponent
String.swift:203
        switch fixedSelf.startOfLastPathComponent {
: String.CharacterView.Index { 0220 precondition(!endsWith("/") && characters.count > 1) 0221 0222 let characterView = characters 0223 let startPos = characterView.startIndex 0224 let endPosition = characterView.endIndex 0225 var currentPosition = endPosition 0226 0227 while currentPosition > startPos { 0228 let previousPosition = currentPosition.predecessor() 0229 if characterView[previousPosition] == "/" { 0230 break 0231 } 0232 currentPosition = previousPosition 0233 } 0234 0235 return currentPosition 0236 } 0237 0238 func fixSlashes
String.swift:197
        let fixedSelf = fixSlashes()
(compress compress: Bool = true, stripTrailing: Bool = true) -> String { 0239 if self == "/" { 0240 return self 0241 } 0242 0243 var result = self 0244 0245 if compress { 0246 result.withMutableCharacters { characterView in 0247 let startPosition = characterView.startIndex 0248 var endPosition = characterView.endIndex 0249 var currentPosition = startPosition 0250 0251 while currentPosition < endPosition { 0252 if characterView[currentPosition] == "/" { 0253 var afterLastSlashPosition = currentPosition 0254 while afterLastSlashPosition < endPosition && characterView[afterLastSlashPosition] == "/" { 0255 afterLastSlashPosition = afterLastSlashPosition.successor() 0256 } 0257 if afterLastSlashPosition != currentPosition.successor() { 0258 characterView.replaceRange(currentPosition ..< afterLastSlashPosition, with: ["/"]) 0259 endPosition = characterView.endIndex 0260 } 0261 currentPosition = afterLastSlashPosition 0262 } else { 0263 currentPosition = currentPosition.successor() 0264 } 0265 } 0266 } 0267 } 0268 0269 if stripTrailing && result.endsWith("/") { 0270 result.removeAtIndex(result.characters.endIndex.predecessor()) 0271 } 0272 0273 return result 0274 } 0275 } 0276 0277 extension String { 0278 public init(percentEncoded: String) throws { 0279 struct Error: ErrorType, CustomStringConvertible { 0280 let description: String 0281 } 0282 0283 let spaceCharacter: UInt8 = 32 0284 let percentCharacter: UInt8 = 37 0285 let plusCharacter: UInt8 = 43 0286 0287 var encodedBytes: [UInt8] = [] + percentEncoded.utf8 0288 var decodedBytes: [UInt8] = [] 0289 var i = 0 0290 0291 while i < encodedBytes.count { 0292 let currentCharacter = encodedBytes[i] 0293 0294 switch currentCharacter { 0295 case percentCharacter: 0296 let unicodeA = UnicodeScalar(encodedBytes[i + 1]) 0297 let unicodeB = UnicodeScalar(encodedBytes[i + 2]) 0298 0299 let hexString = "\(unicodeA)\(unicodeB)" 0300 0301 0302 0303 guard let character = Int(hexString, radix: 16) else { 0304 throw Error(description: "Invalid string") 0305 } 0306 0307 decodedBytes.append(UInt8(character)) 0308 i += 3 0309 0310 case plusCharacter: 0311 decodedBytes.append(spaceCharacter) 0312 i += 1 0313 0314 default: 0315 decodedBytes.append(currentCharacter) 0316 i += 1 0317 } 0318 } 0319 0320 var string = "" 0321 var decoder = UTF8() 0322 var generator = decodedBytes.generate() 0323 var finished = false 0324 0325 while !finished { 0326 let decodingResult = decoder.decode(&generator) 0327 switch decodingResult { 0328 case .Result(let char): string.append(char) 0329 case .EmptyInput: finished = true 0330 case .Error: 0331 throw Error(description: "UTF-8 decoding failed") 0332 } 0333 } 0334 0335 self.init(string) 0336 } 0337 }