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

如何用Swift 5.7的RegexBuilder捕获10个以上内容?

解决Swift RegexBuilder捕获项超过10个的编译错误

问题场景

假设我们有一行人员信息:

Sweeper 30 1992-09-22 China/Beijing - 0 2020-07-07 Mary/Linda - Pizza/Lemon

从左到右依次对应:姓名、年龄、出生日期、出生国家、出生城市、子女数量、结婚日期(可选)、妻子姓名(可选)、前妻姓名(可选)、喜爱食物、最不喜爱食物。

使用Swift 5.7的RegexBuilder编写匹配正则时,会遇到无法在合理时间内完成类型检查的错误(若将可选部分设为必填,错误会明确为Ambiguous use of 'buildPartialBlock(accumulated:next:)')。

原因分析

RegexComponentBuilder的buildPartialBlock重载仅支持最多10个顶层捕获项,当正则中的捕获项(包括Capture/TryCapture以及隐式捕获的分组)超过这个数量时,编译器无法解析对应的类型,从而报错。

解决方案:用Group合并捕获项

和SwiftUI中用Group合并视图的思路一致,我们可以把逻辑相关的多个捕获项打包到Group中,将其转化为一个复合捕获元组(或自定义结构体实例),从而减少顶层捕获项的总数,使其控制在10个以内。

修改后的正则代码

import RegexBuilder
import Foundation

// 可根据需求定义结构体优化数据提取(可选)
struct BirthPlace {
    let country: Substring
    let city: Substring
}

struct MarriageDetails {
    let date: Date
    let spouse: Substring?
    let exSpouse: Substring?
}

struct FoodPreferences {
    let favourite: Substring
    let leastFavourite: Substring
}

let regex = Regex {
    // 1. 姓名
    Capture { /[a-zA-Z ]+/ }
    " "
    // 2. 年龄(转Int)
    TryCapture { OneOrMore(.digit) } transform: { Int($0) }
    " "
    // 3. 出生日期(转Date)
    Capture(.iso8601Date(timeZone: .gmt))
    " "
    // 4. 出生地(合并为结构体)
    Group {
        /[a-zA-Z ]+/
        "/"
        /[a-zA-Z ]+/
    } transform: { BirthPlace(country: $0.0, city: $0.1) }
    " - "
    // 5. 子女数量(转Int)
    TryCapture { OneOrMore(.digit) } transform: { Int($0) }
    // 6. 婚姻信息(可选,合并为结构体)
    Optionally {
        " "
        Group {
            Capture(.iso8601Date(timeZone: .gmt))
            Optionally {
                " "
                Group {
                    /[a-zA-Z ]+/
                    Optionally {
                        "/"
                        /[a-zA-Z ]+/
                    }
                }
            }
        } transform: {
            MarriageDetails(
                date: $0.0,
                spouse: $0.1?.0,
                exSpouse: $0.1?.1
            )
        }
    }
    " - "
    // 7. 食物偏好(合并为结构体)
    Group {
        /[a-zA-Z ]+/
        "/"
        /[a-zA-Z ]+/
    } transform: { FoodPreferences(favourite: $0.0, leastFavourite: $0.1) }
}

代码说明

  1. 合并捕获项:将出生国家/城市、婚姻相关信息、食物偏好分别打包到Group中,原本的多个捕获项被合并为单个顶层捕获(或结构体实例),顶层捕获总数降至7个,符合RegexBuilder的限制。
  2. 结构体优化:通过transform将Group的捕获结果转为自定义结构体,后续提取数据时无需手动解析嵌套元组,代码更易读维护。
  3. 保持单一正则:全程用一个正则处理整行内容,避免拆分多个正则增加复杂度,适合处理格式杂乱的文件场景。

提取匹配结果示例

let input = "Sweeper 30 1992-09-22 China/Beijing - 0 2020-07-07 Mary/Linda - Pizza/Lemon"
if let match = input.firstMatch(of: regex) {
    let name = match.1
    let age = match.2
    let birthDate = match.3
    let birthPlace = match.4
    let childrenCount = match.5
    let marriageDetails = match.6
    let foodPreferences = match.7
    
    // 输出示例
    print("姓名:\(name)")
    print("出生地:\(birthPlace.country)-\(birthPlace.city)")
    if let marriage = marriageDetails {
        print("结婚日期:\(marriage.date)")
        print("配偶:\(marriage.spouse ?? "无")")
        print("前配偶:\(marriage.exSpouse ?? "无")")
    }
}

内容的提问来源于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 11:40:31