“\“在字符串表示正则语义中的作用

在多数语言中,字符串中的"\"会作为转义字符串出现,用以将紧跟其后的字符转义,拓展字符的使用范围。但是在表示正则语义时,"\"会让一些使用场景显得很别扭.

别扭的"\\"

有这样一个场景:有一个文件名数组,需要从中筛选出以"json"结尾的文件名,在iOS中使用传统的正则匹配大概会这样:

Swift 复制代码
        let files = ["filea.txt", "fileb.json", "filec.json", "filed.pdf"];
        let regex = try? NSRegularExpression(pattern: ".*\\.json", options: NSRegularExpression.Options.caseInsensitive)
        let result = files.filter( { (regex?.matches(in: $0, range: NSRange(location: 0, length: $0.count)))?.isEmpty == false } )
        
        print("result:\(result)");

这时就会发现本来只是需要转义"."的"\"需要出现两次,为什么? 这里实际上经历了两个阶段的解析:

  • 所在语言的字符串解析:将"\\."解析为 \.
  • 正则引擎的正则解析: 将 \. 解析为 .

为什么必须是"\\"

在正则表达式(ERE)中, 由于"."有特殊元字符含义,所以使用其本来的意义时就需要使用"\."来表达.

而在swift中,"\"也是一个特殊含义的字符: 转义字符, 所以直接出现的"\"会被认为应该和紧跟其后的字符连起来组合称为一个新字符使用, 所以单独使用"\"会被认为是转义字符,而不是"\"本身,当需要表示"\"时就需要使用"\\"来表示一个真正意义上的"\". 所以在正则引擎中的 \. 在字符串中就会被表示成"\\.".

这里还有一个问题,在iOS的字符串中,常见的转义字符并不多:

\n \t \\ \" \r \0 \u{}

所以原则上讲,使用"\."来表示正则中的"."并没有歧义,那为什么不能直接使用"\."来表示呢?最要的原因是防止潜在的隐患.试想一下, 本来在字符串中出现"\"时,正常的逻辑是其后会出现一个需要被转义的字符,然后发现紧跟其后的是字符".", 并不是一个可以被转义的字符, 如果不报错就意味着"\anything"是一个合理的存在,在这种情况下编译器就无法进行正确的静态分析,无法提示错误,也会造成可读性下降(这他么难道是一个我不知道的转义字符). 所以, 不明语义的转义是不被允许的,这样就可以:

  • 防止拼写错误等隐藏bug;
  • 便于进行静态分析,提示错误,增强可阅读性;
  • 保持和其他主流语言(C/C++/Python/JavaScript/Java等)的逻辑一致性

其他实现方式

事实上,在swift中并不是必须使用这种看起来别扭的语法,有很多方式可以避开这种逻辑.

原始字符串

可以使用原始字符串来避开转义逻辑,上边的实现就可以使用

Swift 复制代码
        let regex = try? NSRegularExpression(pattern: #".*\.json"#, options: NSRegularExpression.Options.caseInsensitive)

来进行替换,这样就可以避开所在语言字符串的转义解析.

使用新的API

在Regex中已经直接使用"/pattern/" 来表示匹配模式,上边的实现可以修改为:

Swift 复制代码
 let result = files.filter({ $0.wholeMatch(of: /.*\.json/) != nil })

其他非正则的方式

可以借助于其他非正则封装的方式来实现,比如 `hasSuffix`之类.

相关推荐
四眼蒙面侠1 天前
深入 SwiftWork(第 0 篇):用 SwiftUI 构建一个 Agent 可视化工作台
swift·openagentsdk
sakiko_2 天前
UIKit学习笔记4-使用UITableView制作滚动视图
笔记·学习·ios·swift·uikit
四眼蒙面侠3 天前
深入 Open Agent SDK(番外篇):实战验证——把 SDK 塞进一个 macOS 原生 Agent 应用
swift·claudecode·bmad·agentsdk·openagentsdk
2501_915106323 天前
在Mac上搭建iOS开发环境的详细步骤与注意事项
ide·vscode·macos·ios·个人开发·swift·敏捷流程
harder3214 天前
RMP模式的创新突破
开发语言·学习·ios·swift·策略模式
sakiko_4 天前
UIKit学习笔记2-组件嵌套、滚动视图等
笔记·学习·objective-c·swift·uikit
四眼蒙面侠4 天前
深入 Open Agent SDK(五):会话持久化与安全防线
swift·claudecode·bmad·openagentsdk
茶底世界之下5 天前
诡异!String 参数在闭包里变成了 <uninitialized>,我排查了整整两天
ios·xcode·swift
四眼蒙面侠5 天前
深入 Open Agent SDK(四):多 Agent 协作——子代理、团队与任务编排
swift·agentsdk·openagentsdk