0001    // Regex.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    @_exported import Data
0026    
0027    struct RegexError
Regex.swift:30
    static func errorFromResult(result: Int32, preg: regex_t) -> RegexError {
Regex.swift:71
            throw RegexError.errorFromResult(result, preg: preg)
: ErrorType { 0028 let description: String 0029 0030 static func errorFromResult(result: Int32, preg: regex_t) -> RegexError { 0031 var preg = preg 0032 var buffer = [Int8](count: Int(BUFSIZ), repeatedValue: 0) 0033 regerror(result, &preg, &buffer, buffer.count) 0034 let description = String.fromCString(buffer)! 0035 return RegexError(description: description) 0036 } 0037 } 0038 0039 public final class Regex { 0040 public struct RegexOptions
Regex.swift:47
        public static let Basic =            RegexOptions(rawValue: 0)
Regex.swift:48
        public static let Extended =         RegexOptions(rawValue: 1)
Regex.swift:49
        public static let CaseInsensitive =  RegexOptions(rawValue: 2)
Regex.swift:50
        public static let ResultOnly =       RegexOptions(rawValue: 8)
Regex.swift:51
        public static let NewLineSensitive = RegexOptions(rawValue: 4)
Regex.swift:67
    public init(pattern: String, options: RegexOptions = [.Extended]) throws {
: OptionSetType { 0041 public let rawValue
Regex.swift:44
            self.rawValue = rawValue
: Int32 0042 0043 public init
Regex.swift:47
        public static let Basic =            RegexOptions(rawValue: 0)
Regex.swift:48
        public static let Extended =         RegexOptions(rawValue: 1)
Regex.swift:49
        public static let CaseInsensitive =  RegexOptions(rawValue: 2)
Regex.swift:50
        public static let ResultOnly =       RegexOptions(rawValue: 8)
Regex.swift:51
        public static let NewLineSensitive = RegexOptions(rawValue: 4)
(rawValue: Int32) { 0044 self.rawValue = rawValue 0045 } 0046 0047 public static let Basic = RegexOptions(rawValue: 0) 0048 public static let Extended
Regex.swift:67
    public init(pattern: String, options: RegexOptions = [.Extended]) throws {
= RegexOptions(rawValue: 1) 0049 public static let CaseInsensitive = RegexOptions(rawValue: 2) 0050 public static let ResultOnly = RegexOptions(rawValue: 8) 0051 public static let NewLineSensitive = RegexOptions(rawValue: 4) 0052 } 0053 0054 public struct MatchOptions
Regex.swift:61
        public static let FirstCharacterNotAtBeginningOfLine = MatchOptions(rawValue: REG_NOTBOL)
Regex.swift:62
        public static let LastCharacterNotAtEndOfLine =        MatchOptions(rawValue: REG_NOTEOL)
Regex.swift:79
    public func matches(string: String, options: MatchOptions = []) -> Bool {
Regex.swift:90
    public func groups(string: String, options: MatchOptions = []) -> [String] {
Regex.swift:124
    public func replace(string: String, withTemplate template: String, options: MatchOptions = []) -> String {
: OptionSetType { 0055 public let rawValue
Regex.swift:58
            self.rawValue = rawValue
: Int32 0056 0057 public init(rawValue: Int32) { 0058 self.rawValue = rawValue 0059 } 0060 0061 public static let FirstCharacterNotAtBeginningOfLine = MatchOptions(rawValue: REG_NOTBOL) 0062 public static let LastCharacterNotAtEndOfLine = MatchOptions(rawValue: REG_NOTEOL) 0063 } 0064 0065 var preg = regex_t() 0066 0067 public init(pattern: String, options: RegexOptions = [.Extended]) throws { 0068 let result = regcomp(&preg, pattern, options.rawValue) 0069 0070 if result != 0 { 0071 throw RegexError.errorFromResult(result, preg: preg) 0072 } 0073 } 0074 0075 deinit { 0076 regfree(&preg) 0077 } 0078 0079 public func matches(string: String, options: MatchOptions = []) -> Bool { 0080 var regexMatches = [regmatch_t](count: 1, repeatedValue: regmatch_t()) 0081 let result = regexec(&preg, string, regexMatches.count, &regexMatches, options.rawValue) 0082 0083 if result == 1 { 0084 return false 0085 } 0086 0087 return true 0088 } 0089 0090 public func groups(string: String, options: MatchOptions = []) -> [String] { 0091 var string = string 0092 let maxMatches = 10 0093 var groups = [String]() 0094 0095 while true { 0096 var regexMatches = [regmatch_t](count: maxMatches, repeatedValue: regmatch_t()) 0097 let result = regexec(&preg, string, regexMatches.count, &regexMatches, options.rawValue) 0098 0099 if result == 1 { 0100 break 0101 } 0102 0103 var j = 1 0104 0105 while regexMatches[j].rm_so != -1 { 0106 let start = Int(regexMatches[j].rm_so) 0107 let end = Int(regexMatches[j].rm_eo) 0108 let match = string[string.startIndex.advancedBy(start) ..< string.startIndex.advancedBy(end)] 0109 groups.append(match) 0110 j += 1 0111 } 0112 0113 let offset = Int(regexMatches[0].rm_eo) 0114 if let offsetString = String(string.utf8[string.utf8.startIndex.advancedBy(offset) ..< string.utf8.endIndex]) { 0115 string = offsetString 0116 } else { 0117 break 0118 } 0119 } 0120 0121 return groups 0122 } 0123 0124 public func replace(string: String, withTemplate template: String, options: MatchOptions = []) -> String { 0125 var string = string 0126 let maxMatches = 10 0127 var totalReplacedString: String = "" 0128 0129 while true { 0130 var regexMatches = [regmatch_t](count: maxMatches, repeatedValue: regmatch_t()) 0131 let result = regexec(&preg, string, regexMatches.count, &regexMatches, options.rawValue) 0132 0133 if result == 1 { 0134 break 0135 } 0136 0137 let start = Int(regexMatches[0].rm_so) 0138 let end = Int(regexMatches[0].rm_eo) 0139 0140 var replacedStringArray = Array<UInt8>(string.utf8) 0141 let templateArray = Array<UInt8>(template.utf8) 0142 replacedStringArray.replaceRange(start ..< end, with: templateArray) 0143 0144 guard let _replacedString = try? String(data: Data(bytes: replacedStringArray)) else { 0145 break 0146 } 0147 0148 var replacedString = _replacedString 0149 0150 let templateDelta = template.utf8.count - (end - start) 0151 let templateDeltaIndex = replacedString.utf8.startIndex.advancedBy(Int(end + templateDelta)) 0152 0153 replacedString = String(replacedString.utf8[replacedString.utf8.startIndex ..< templateDeltaIndex]) 0154 0155 totalReplacedString += replacedString 0156 string = String(string.utf8[string.utf8.startIndex.advancedBy(end) ..< string.utf8.endIndex]) 0157 } 0158 0159 return totalReplacedString + string 0160 } 0161 }