Swift正则无法匹配替换含特定URL代码行问题排查
我写了一套正则表达式,用来匹配包含特定URL的Swift代码行,支持带换行、空格的不同格式,匹配后替换该行。这套正则在bash脚本里能正常运行,但放到Swift环境里就失效了。相关正则定义和示例代码如下:
let pattern_1 = "([\\ ]*)" // 用于匹配'.package(url: \"https://example.com/path\",',同时考虑冒号、双引号和逗号之间的空白字符(包括换行)。 let pattern_2 = "\\.package\\([[:space:]]*url[[:space:]]*:[[:space:]]*\\\\"\(escapedUrl)"[[:space:]]*,[[:space:]]*" // 用于匹配'(from|branch|revision|exact):'及以下任意一种格式: // - \"1.0.0\" // - \"some/branch/name\" 或 \"asd1234zxc678qwe\" let pattern_3 = "(from|branch|revision|exact)[[:space:]]*:[\\ ]*\\"[A-z0-9\\.]+\\"" // 匹配'.upToNextMinor'、'.upToNextMajor('后跟\"x.x.x\"及')' let pattern_4 = "\\.[A-z]+[\\ ]*\\([A-z]+:[\\ ]*\\"[0-9\\.]+\\"\\)" // 匹配版本范围,例如\"0.0.0\"..<\"1.0.0\"或\"0.0.0\"...\"1.0.0\" let pattern_5 = "\\"([0-9]+\\.{0,1})+\\"\\.{2}(\\.|<)\\"([0-9]+\\.{0,1})+\\"" // 用于查找闭合括号或逗号,允许括号前存在空格和换行 let pattern_6 = "[[:space:]]*\\)([,]*)" // 完整正则 let pattern = "\(pattern_1)\(pattern_2)(\(pattern_3)|\(pattern_4)|\(pattern_5))\(pattern_6)"
假设escapedUrl为https://bitbucket.org/XXX/XXX,待匹配的示例文本:
dependencies: [ .package(url: \"https://bitbucket.org/XXX/XXX\", .upToNextMinor(from:\"1.0.0\")) ],
或:
dependencies: [ .package(url: \"https://bitbucket.org/XXX/XXX\", .upToNextMinor(from:\"1.0.0\")) ],
核心失效原因
1. 字符类[A-z]的兼容性问题
[A-z]在ASCII表中包含了Z(90)到a(97)之间的非字母字符(比如[、\、_等),bash的正则引擎做了兼容处理,只匹配大小写字母,但Swift使用的NSRegularExpression严格遵循ASCII规则,会把这些非字母字符也纳入匹配范围,导致pattern_3、pattern_4无法精准匹配目标代码中的字母内容,进而导致整个正则匹配失败。
正确写法应替换为[A-Za-z],明确只匹配大小写英文字母。
2. 双引号转义错误
在Swift字符串中,要生成正则里的\"(用于匹配代码中的双引号),需要写成\\\":
- Swift字符串中单个
\是转义符,所以要生成正则的\需要写\\; - 要生成正则的
\",则需要写成\\\"(Swift转义后对应正则的\")。
但pattern_2中的\\\\"\(escapedUrl)"会生成正则里的\\"https://xxx...",多了一个不必要的反斜杠,导致正则把双引号当成普通字符,无法匹配代码里的"https://xxx..."格式。
修正后的pattern_2应为:
let pattern_2 = "\\.package\\([[:space:]]*url[[:space:]]*:[[:space:]]*\\\"\(escapedUrl)\\\"[[:space:]]*,[[:space:]]*"
3. 空白字符匹配范围不全
pattern_3里的:[\\ ]*只匹配空格,但注释明确要求支持换行等空白字符,这里应替换为:[[:space:]]*(和pattern_2保持一致),否则当冒号和双引号之间有换行时,pattern_3无法匹配,导致整个正则失效。
4. 正则模式未适配跨行场景
Swift的NSRegularExpression默认不允许.匹配换行符,虽然你的正则主要用[:space:]处理换行,但如果后续涉及.的匹配(比如pattern_4里的\\.[A-z]+),若目标内容存在换行分隔的情况,需要启用dotMatchesLineSeparators选项,确保.能匹配换行符。
内容的提问来源于stack exchange,提问作者mrjimoy_05

