如何创建可输出自定义类型的Swift Regex?
如何创建输出自定义类型的Swift Regex?
解决方案:使用Regex.map()转换输出类型
最简洁可靠的方式是先定义捕获原始元组的正则,再通过map方法将元组转换为自定义类型,示例如下:
import Foundation struct Person { let name: String let age: Int let dob: Date } let line = "John (30) 1992-09-22" // 1. 定义捕获原始元组的基础正则 let baseRegex = Regex { Capture(/\w+/) " (" TryCapture(/\d+/) { Int($0) } ") " Capture(.iso8601Date(timeZone: .gmt)) } // 2. 通过map将元组输出转换为Person类型 let personRegex = baseRegex.map { _, name, age, dob in Person(name: String(name), age: age, dob: dob) } // 使用示例 if let match = line.wholeMatch(of: personRegex) { let person = match.output print(person.name) // 输出: John print(person.age) // 输出: 30 print(person.dob) // 输出: 1992-09-22 00:00:00 +0000 }
此时personRegex的类型为Regex<Person>,匹配后的output直接返回Person实例,完全避开了元组的使用。
你之前代码崩溃的原因
你尝试在外层Capture中使用transform闭包,但Capture的transform参数接收的是整个Capture匹配到的Substring,而非内部多个Capture组成的元组。强行将Substring转换为元组类型,必然导致运行时类型转换崩溃。
备选方案:构建器内直接转换(不推荐)
如果一定要在正则构建器内完成转换,可以用TryCapture包裹整个匹配逻辑,手动解析匹配结果,但需要额外处理错误,不如map简洁:
import Foundation struct Person { let name: String let age: Int let dob: Date } struct RegexTransformError: Error {} let line = "John (30) 1992-09-22" let personRegex = Regex { TryCapture { Capture(/\w+/) " (" TryCapture(/\d+/) { Int($0) } ") " Capture(.iso8601Date(timeZone: .gmt)) } transform: { match in guard let innerMatch = match.wholeMatch(of: baseRegex) else { throw RegexTransformError() } let (_, name, age, dob) = innerMatch.output return Person(name: String(name), age: age, dob: dob) } }
内容的提问来源于stack exchange,提问作者Sweeper
相关产品推荐
相关产品推荐

