[Swift]正则表达式工具类

正则表达式工具类

  1 import Foundation
  2  
  3 //基于NSRegularExpression api 的正则处理工具类
  4 public struct Regex {
  5  
  6     private let regularExpression: NSRegularExpression
  7      
  8     //使用正则表达式进行初始化
  9     public init(_ pattern: String, options: Options = []) throws {
 10         regularExpression = try NSRegularExpression(
 11             pattern: pattern,
 12             options: options.toNSRegularExpressionOptions
 13         )
 14     }
 15      
 16     //正则匹配验证(true表示匹配成功)
 17     public func matches(_ string: String) -> Bool {
 18         return firstMatch(in: string) != nil
 19     }
 20      
 21     //获取第一个匹配结果
 22     public func firstMatch(in string: String) -> Match? {
 23         let firstMatch = regularExpression
 24             .firstMatch(in: string, options: [],
 25                         range: NSRange(location: 0, length: string.utf16.count))
 26             .map { Match(result: $0, in: string) }
 27         return firstMatch
 28     }
 29      
 30     //获取所有的匹配结果
 31     public func matches(in string: String) -> [Match] {
 32         let matches = regularExpression
 33             .matches(in: string, options: [],
 34                      range: NSRange(location: 0, length: string.utf16.count))
 35             .map { Match(result: $0, in: string) }
 36         return matches
 37     }
 38      
 39     //正则替换
 40     public func replacingMatches(in input: String, with template: String,
 41                                  count: Int? = nil) -> String {
 42         var output = input
 43         let matches = self.matches(in: input)
 44         let rangedMatches = Array(matches[0..<min(matches.count, count ?? .max)])
 45         for match in rangedMatches.reversed() {
 46             let replacement = match.string(applyingTemplate: template)
 47             output.replaceSubrange(match.range, with: replacement)
 48         }
 49          
 50         return output
 51     }
 52 }
 53  
 54 //正则匹配可选项
 55 extension Regex {
 56     /// Options 定义了正则表达式匹配时的行为
 57     public struct Options: OptionSet {
 58          
 59         //忽略字母
 60         public static let ignoreCase = Options(rawValue: 1)
 61          
 62         //忽略元字符
 63         public static let ignoreMetacharacters = Options(rawValue: 1 << 1)
 64          
 65         //默认情况下,“^”匹配字符串的开始和结束的“$”匹配字符串,无视任何换行。
 66         //使用这个配置,“^”将匹配的每一行的开始,和“$”将匹配的每一行的结束。
 67         public static let anchorsMatchLines = Options(rawValue: 1 << 2)
 68          
 69         ///默认情况下,"."匹配除换行符(\n)之外的所有字符。使用这个配置,选项将允许“.”匹配换行符
 70         public static let dotMatchesLineSeparators = Options(rawValue: 1 << 3)
 71          
 72         //OptionSet的 raw value
 73         public let rawValue: Int
 74          
 75         //将Regex.Options 转换成对应的 NSRegularExpression.Options
 76         var toNSRegularExpressionOptions: NSRegularExpression.Options {
 77             var options = NSRegularExpression.Options()
 78             if contains(.ignoreCase) { options.insert(.caseInsensitive) }
 79             if contains(.ignoreMetacharacters) {
 80                 options.insert(.ignoreMetacharacters) }
 81             if contains(.anchorsMatchLines) { options.insert(.anchorsMatchLines) }
 82             if contains(.dotMatchesLineSeparators) {
 83                 options.insert(.dotMatchesLineSeparators) }
 84             return options
 85         }
 86          
 87         //OptionSet 初始化
 88         public init(rawValue: Int) {
 89             self.rawValue = rawValue
 90         }
 91     }
 92 }
 93  
 94 //正则匹配结果
 95 extension Regex {
 96     // Match 封装有单个匹配结果
 97     public class Match: CustomStringConvertible {
 98         //匹配的字符串
 99         public lazy var string: String = {
100             return String(describing: self.baseString[self.range])
101         }()
102          
103         //匹配的字符范围
104         public lazy var range: Range<String.Index> = {
105             return Range(self.result.range, in: self.baseString)!
106         }()
107          
108         //正则表达式中每个捕获组匹配的字符串
109         public lazy var captures: [String?] = {
110             let captureRanges = stride(from: 0, to: result.numberOfRanges, by: 1)
111                 .map(result.range)
112                 .dropFirst()
113                 .map { [unowned self] in
114                     Range($0, in: self.baseString)
115             }
116              
117             return captureRanges.map { [unowned self] captureRange in
118                 if let captureRange = captureRange {
119                     return String(describing: self.baseString[captureRange])
120                 }
121                  
122                 return nil
123             }
124         }()
125          
126         private let result: NSTextCheckingResult
127          
128         private let baseString: String
129          
130         //初始化
131         internal init(result: NSTextCheckingResult, in string: String) {
132             precondition(
133                 result.regularExpression != nil,
134                 "NSTextCheckingResult必需使用正则表达式"
135             )
136              
137             self.result = result
138             self.baseString = string
139         }
140          
141         //返回一个新字符串,根据“模板”替换匹配的字符串。
142         public func string(applyingTemplate template: String) -> String {
143             let replacement = result.regularExpression!.replacementString(
144                 for: result,
145                 in: baseString,
146                 offset: 0,
147                 template: template
148             )
149              
150             return replacement
151         }
152          
153         //信息
154         public var description: String {
155             return "Match<\"\(string)\">"
156         }
157     }
158 }

 

测试示例:

1、验证字符串格式

 1 //初始化正则工具类
 2 let pattern = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$"
 3 let regex = try! Regex(pattern)
 4  
 5 //验证邮箱地址
 6 let email = "[email protected]"
 7 if regex.matches(email) {
 8     print("正确邮箱格式")
 9 }else{
10     print("错误邮箱格式")
11 }
测试结果:
正确邮箱格式

2、提取字符串

(1)获取第一个匹配结果

 1 //初始化正则工具类
 2 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)"
 3 let regex = try! Regex(pattern)
 4  
 5 //原始字符串
 6 let str = "张三:123,李四:456,王五:789"
 7  
 8 //获取第一个匹配对象
 9 if let first = regex.firstMatch(in: str) {
10     print("--- 第一个匹配结果  ---")
11     print(first)
12     print("匹配字符串:", first.string)
13     print("捕获组:", first.captures[0]!, first.captures[1]!)
14     print("匹配范围:", first.range)
15 }

测试结果:

1 --- 第一个匹配结果  ---
2 Match<"张三:123">
3 匹配字符串: 张三:123
4 捕获组: 张三 123
5 匹配范围: Index(_compoundOffset: 0, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 1)..<Index(_compoundOffset: 24, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 1)

(2)获取所有的匹配结果 

 1 //初始化正则工具类
 2 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)"
 3 let regex = try! Regex(pattern)
 4  
 5 //原始字符串
 6 let str = "张三:123,李四:456,王五:789"
 7  
 8 //获取第一个匹配对象
 9 for match in regex.matches(in: str) {
10     print("\n--- 匹配结果  ---")
11     print(match)
12     print("匹配字符串:", match.string)
13     print("捕获组:", match.captures[0]!, match.captures[1]!)
14     print("匹配范围:", match.range)
15 }

测试结果:

 1 --- 匹配结果  ---
 2 Match<"张三:123">
 3 匹配字符串: 张三:123
 4 捕获组: 张三 123
 5 匹配范围: Index(_compoundOffset: 0, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 1)..<Index(_compoundOffset: 24, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 1)
 6 
 7 --- 匹配结果  ---
 8 Match<"李四:456">
 9 匹配字符串: 李四:456
10 捕获组: 李四 456
11 匹配范围: Index(_compoundOffset: 28, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 1)..<Index(_compoundOffset: 52, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 1)
12 
13 --- 匹配结果  ---
14 Match<"王五:789">
15 匹配字符串: 王五:789
16 捕获组: 王五 789
17 匹配范围: Index(_compoundOffset: 56, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 1)..<Index(_compoundOffset: 80, _utf8Buffer: Swift._ValidUTF8Buffer<Swift.UInt32>(_biasedBits: 0), _graphemeStrideCache: 0)

3、字符串替换

(1)简单的替换

 1 //初始化正则工具类
 2 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)"
 3 let regex = try! Regex(pattern)
 4  
 5 //原始字符串
 6 let str = "张三:123,李四:456,王五:789"
 7  
 8 //只替换第1个匹配项
 9 let out1 = regex.replacingMatches(in: str, with: "***", count: 1)
10 //替换所有匹配项
11 let out2 = regex.replacingMatches(in: str, with: "***")
12    
13 //输出结果
14 print("原始的字符串:", str)
15 print("替换第1个匹配项:", out1)
16 print("替换所有匹配项:", out2)

测试结果:

1 原始的字符串: 张三:123,李四:456,王五:789
2 替换第1个匹配项: ***,李四:456,王五:789
3 替换所有匹配项: ***,***,***

(2)捕获组替换

 1 //初始化正则工具类
 2 let pattern = "([\\u4e00-\\u9fa5]+):([\\d]+)"
 3 let regex = try! Regex(pattern)
 4  
 5 //原始字符串
 6 let str = "张三:123,李四:456,王五:789"
 7  
 8 //只替换第1个匹配项
 9 let out1 = regex.replacingMatches(in: str, with: "$1的电话是$2", count: 1)
10 //替换所有匹配项
11 let out2 = regex.replacingMatches(in: str, with: "$1的电话是$2")
12    
13 //输出结果
14 print("原始的字符串:", str)
15 print("替换第1个匹配项:", out1)
16 print("替换所有匹配项:", out2)

测试结果:

1 原始的字符串: 张三:123,李四:456,王五:789
2 替换第1个匹配项: 张三的电话是123,李四:456,王五:789
3 替换所有匹配项: 张三的电话是123,李四的电话是456,王五的电话是789

4、其他常用的正则表达式

 1 //用户名验证(允许使用小写字母、数字、下滑线、横杠,一共3~16个字符)
 2 ^[a-z0-9_-]{3,16}$
 3  
 4 //Email验证
 5 ^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$
 6  
 7 //手机号码验证:以1开头的11位纯数字串
 8 ^1[0-9]{10}$
 9  
10 //URL验证
11 ^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
12  
13 //IP地址验证
14 ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
15  
16 //html标签验证
17 ^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$

猜你喜欢

转载自www.cnblogs.com/strengthen/p/10647126.html