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

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

别扭的"\\"

有这样一个场景:有一个文件名数组,需要从中筛选出以"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`之类.

相关推荐
软泡芙20 小时前
【IOS】 Swift Package Manager (SPM) 指南
网络·ios·swift
东坡肘子21 小时前
不是模型变慢了,是任务变大了 -- 肘子的 Swift 周报 #146
人工智能·swiftui·swift
大龄秃头程序员2 天前
Sendable 不是“能跑就行”:Swift Concurrency 下的实战踩坑与架构落地指南
swift
大熊猫侯佩2 天前
WWDC26 全新 SwiftData 的 .codable 宏选项:它不是泛型专用胶水
数据库·swift·apple
大龄秃头程序员2 天前
Swift 并发实战:从 Task 到 Actor 重入性,我掉进了“逻辑不一致”的坑
swift
LinXunFeng3 天前
给 Flutter 插件加上 Swift Package Manager 支持
flutter·swift
大龄秃头程序员3 天前
Swift 面试反直觉:Property Wrapper 真的拿不到宿主 self 吗?
swift
FeliksLv3 天前
从 +load 到 Swift Macros:自动注册的演进与实践
ios·objective-c·swift
语歌3 天前
AI 语言学习系统的工程边界:为什么 LLM 不该负责复习排期
人工智能·swift