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

Swift 5.7含5个捕获组的复杂正则导致编译器类型检查超时如何解决?

修复Swift正则表达式编译时类型检查超时错误

问题描述

我编写了如下Swift代码:

let regex = Regex {
        let newline = #/\r|\n|\r\n/#
        let doubleNewline = Repeat(newline, count: 2)
        let dateFormatter = DateFormatter()
        
        "# Title"
        newline
        Capture { ZeroOrMore(.any) }
        
        doubleNewline
        
        "# Subtitle"
        newline
        Capture { ZeroOrMore(.any) }
        
        doubleNewline
        
        "# Created at"
        newline
        TryCapture { OneOrMore(.any) } transform: { createdDateString in
            dateFormatter.date(from: String(createdDateString))
        }
        
        doubleNewline
        
        "# Exported at"
        newline
        TryCapture { OneOrMore(.any) } transform: { exportedDateString in
            dateFormatter.date(from: String(exportedDateString))
        }
        
        doubleNewline
        
        "# Article count"
        newline
        Capture {
            .localizedInteger
        }
        
        doubleNewline
        
        "# Articles"
        newline
        ZeroOrMore {
            #/[\s\S]/#
        }
        newline
    }

运行时出现错误提示:

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

我尝试了以下两种方法,但均未解决该错误:

  • 为regex添加类型注解:
    let regex: Regex<(Substring, Substring, Substring, Date, Date, Int)> = Regex { ... }
    
  • 为两个TryCapture的transform闭包显式指定类型:
    TryCapture { OneOrMore(.any) } transform: { (createdDateString: Substring) -> Date in
        dateFormatter.date(from: String(createdDateString))
    }
    

解决方案

核心思路:拆分复杂正则为独立子组件

Swift的Regex DSL在处理大型嵌套结构时,编译器的类型推导会因复杂度过载而超时。解决关键是将正则中的每个独立逻辑区块提取为单独的RegexComponent变量,降低单表达式的推导压力。同时注意代码中遗漏的日期格式化器配置,否则即使编译通过也无法正确解析日期。

修复后的代码

// 1. 定义通用基础组件
let newline = #/\r|\n|\r\n/#
let doubleNewline = Repeat(newline, count: 2)

// 2. 配置日期格式化器(必须设置匹配实际数据的格式)
let dateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" // 根据你的日期格式调整
    formatter.locale = Locale(identifier: "en_US_POSIX")
    return formatter
}()

// 3. 拆分每个独立的正则区块
let titleBlock = Regex {
    "# Title"
    newline
    Capture { ZeroOrMore(.any) }
}

let subtitleBlock = Regex {
    "# Subtitle"
    newline
    Capture { ZeroOrMore(.any) }
}

let createdDateBlock = Regex {
    "# Created at"
    newline
    TryCapture { OneOrMore(.any) } transform: { (str: Substring) -> Date? in
        dateFormatter.date(from: String(str))
    }
}

let exportedDateBlock = Regex {
    "# Exported at"
    newline
    TryCapture { OneOrMore(.any) } transform: { (str: Substring) -> Date? in
        dateFormatter.date(from: String(str))
    }
}

let articleCountBlock = Regex {
    "# Article count"
    newline
    Capture { .localizedInteger }
}

let articlesBlock = Regex {
    "# Articles"
    newline
    ZeroOrMore { #/[\s\S]/# }
    newline
}

// 4. 组合所有子区块生成最终正则
let regex = Regex {
    titleBlock
    doubleNewline
    subtitleBlock
    doubleNewline
    createdDateBlock
    doubleNewline
    exportedDateBlock
    doubleNewline
    articleCountBlock
    doubleNewline
    articlesBlock
}

额外优化建议

  • 将dateFormatter改为惰性初始化闭包,避免重复创建,同时确保格式配置正确。
  • 若ZeroOrMore(.any)存在过度匹配问题,可替换为更精确的规则,比如ZeroOrMore(.verticalWhitespace.inverted),限制匹配到下一个换行前的内容。
  • 拆分后的子组件更易维护和调试,后续修改单个区块不会影响整体正则结构。

内容的提问来源于stack exchange,提问作者Nil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 19:45:56