You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建可输出自定义类型的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 13:41:13