Swift - 封装一个正则表达式工具类(附:正则替换、正则匹配样例)
除了验证数据外,我们还可以使用正则表达式进行文字替换、或者提取工作。下面通过样例进行演示。
一、封装一个正则工具类(Regex.swift)
由于 NSRegularExpression 使用起来十分繁琐,为方便使用,我们首先对它进行封装。增加一些常用的正则处理方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | import Foundation /// 基于NSRegularExpression api 的正则处理工具类 public struct Regex { private let regularExpression: NSRegularExpression //使用正则表达式进行初始化 public init (_ pattern: String , options: Options = []) throws { regularExpression = try NSRegularExpression ( pattern: pattern, options: options.toNSRegularExpressionOptions ) } //正则匹配验证(true表示匹配成功) public func matches(_ string: String ) -> Bool { return firstMatch( in : string) != nil } //获取第一个匹配结果 public func firstMatch( in string: String ) -> Match ? { let firstMatch = regularExpression .firstMatch( in : string, options: [], range: NSRange (location: 0, length: string.utf16.count)) . map { Match (result: $0, in : string) } return firstMatch } //获取所有的匹配结果 public func matches( in string: String ) -> [ Match ] { let matches = regularExpression .matches( in : string, options: [], range: NSRange (location: 0, length: string.utf16.count)) . map { Match (result: $0, in : string) } return matches } //正则替换 public func replacingMatches( in input: String , with template: String , count: Int ? = nil ) -> String { var output = input let matches = self .matches( in : input) let rangedMatches = Array (matches[0..< min (matches.count, count ?? . max )]) for match in rangedMatches.reversed() { let replacement = match.string(applyingTemplate: template) output.replaceSubrange(match.range, with: replacement) } return output } } //正则匹配可选项 extension Regex { /// Options 定义了正则表达式匹配时的行为 public struct Options : OptionSet { //忽略字母 public static let ignoreCase = Options (rawValue: 1) //忽略元字符 public static let ignoreMetacharacters = Options (rawValue: 1 << 1) //默认情况下,“^”匹配字符串的开始和结束的“$”匹配字符串,无视任何换行。 //使用这个配置,“^”将匹配的每一行的开始,和“$”将匹配的每一行的结束。 public static let anchorsMatchLines = Options (rawValue: 1 << 2) ///默认情况下,"."匹配除换行符(\n)之外的所有字符。使用这个配置,选项将允许“.”匹配换行符 public static let dotMatchesLineSeparators = Options (rawValue: 1 << 3) //OptionSet的 raw value public let rawValue: Int //将Regex.Options 转换成对应的 NSRegularExpression.Options var toNSRegularExpressionOptions: NSRegularExpression . Options { var options = NSRegularExpression . Options () if contains(.ignoreCase) { options.insert(.caseInsensitive) } if contains(.ignoreMetacharacters) { options.insert(.ignoreMetacharacters) } if contains(.anchorsMatchLines) { options.insert(.anchorsMatchLines) } if contains(.dotMatchesLineSeparators) { options.insert(.dotMatchesLineSeparators) } return options } //OptionSet 初始化 public init (rawValue: Int ) { self .rawValue = rawValue } } } //正则匹配结果 extension Regex { // Match 封装有单个匹配结果 public class Match : CustomStringConvertible { //匹配的字符串 public lazy var string: String = { return String (describing: self .baseString[ self .range]) }() //匹配的字符范围 public lazy var range: Range < String . Index > = { return Range ( self .result.range, in : self .baseString)! }() //正则表达式中每个捕获组匹配的字符串 public lazy var captures: [ String ?] = { let captureRanges = stride(from: 0, to: result.numberOfRanges, by: 1) . map (result.range) .dropFirst() . map { [ unowned self ] in Range ($0, in : self .baseString) } return captureRanges. map { [ unowned self ] captureRange in if let captureRange = captureRange { return String (describing: self .baseString[captureRange]) } return nil } }() private let result: NSTextCheckingResult private let baseString: String //初始化 internal init (result: NSTextCheckingResult , in string: String ) { precondition( result.regularExpression != nil , "NSTextCheckingResult必需使用正则表达式" ) self .result = result self .baseString = string } //返回一个新字符串,根据“模板”替换匹配的字符串。 public func string(applyingTemplate template: String ) -> String { let replacement = result.regularExpression!.replacementString( for : result, in : baseString, offset: 0, template: template ) return replacement } //藐视信息 public var description: String { return "Match<\"\(string)\">" } } } |
二、使用样例
1,验证字符串格式
下面样例验证一个邮箱地址的格式是否正确。
1 2 3 4 5 6 7 8 9 10 11 | //初始化正则工具类 let pattern = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$" let regex = try! Regex (pattern) //验证邮箱地址 let mailAddress = "admin@hangge.com" if regex.matches(mailAddress) { print ( "邮箱地址格式正确" ) } else { print ( "邮箱地址格式有误" ) } |
2,提取字符串
(1)获取第一个匹配结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //初始化正则工具类 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)" let regex = try! Regex (pattern) //原始字符串 let str = "王大锤:123456,李子明:23457,李洛克:110" //获取第一个匹配对象 if let first = regex.firstMatch( in : str) { print ( "--- 第一个匹配结果 ---" ) print (first) print ( "匹配字符串:" , first.string) print ( "捕获组:" , first.captures[0]!, first.captures[1]!) print ( "匹配范围:" , first.range) } |
(2)获取所有的匹配结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //初始化正则工具类 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)" let regex = try! Regex (pattern) //原始字符串 let str = "王大锤:123456,李子明:23457,李洛克:110" //获取第一个匹配对象 for match in regex.matches( in : str) { print ( "\n--- 匹配结果 ---" ) print (match) print ( "匹配字符串:" , match.string) print ( "捕获组:" , match.captures[0]!, match.captures[1]!) print ( "匹配范围:" , match.range) } |
3,字符串替换
(1)简单的替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //初始化正则工具类 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)" let regex = try! Regex (pattern) //原始字符串 let str = "王大锤:123456,李子明:23457,李洛克:110" //只替换第1个匹配项 let out1 = regex.replacingMatches( in : str, with: "***" , count: 1) //替换所有匹配项 let out2 = regex.replacingMatches( in : str, with: "***" ) //输出结果 print ( "原始的字符串:" , str) print ( "替换第1个匹配项:" , out1) print ( "替换所有匹配项:" , out2) |
(2)捕获组替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //初始化正则工具类 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)" let regex = try! Regex (pattern) //原始字符串 let str = "王大锤:123456,李子明:23457,李洛克:110" //只替换第1个匹配项 let out1 = regex.replacingMatches( in : str, with: "$1的电话是$2" , count: 1) //替换所有匹配项 let out2 = regex.replacingMatches( in : str, with: "$1的电话是$2" ) //输出结果 print ( "原始的字符串:" , str) print ( "替换第1个匹配项:" , out1) print ( "替换所有匹配项:" , out2) |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 叶落花开的博客!
评论