美文网首页Swift
Swift 正则Regex

Swift 正则Regex

作者: zzzworm | 来源:发表于2023-11-14 16:34 被阅读0次

Swift 正则Regex

在Swift 5.7版本中,Apple在Swift对正则表达式的支持做了一个重大的更新,不但提供了一个Regex的新类型代表正则表达式,同时还提供了一个DSL语法来创建正则表达式。

  • SE-0350 introduces a new Regex type
  • SE-0351 introduces a result builder-powered DSL for creating regular expressions.
  • SE-0354 adds the ability co create a regular expression using /.../ rather than going through Regex and a string.
  • SE-0357 adds many new string processing algorithms based on regular expressions.

这对编写正则表达式程序提供了极大的方便。在Swift之前的版本创建正则表达式仍然是使用NSRegularExpression,创建方式如下:

// Match and capture one or more digits
let pattern = #"(\d+)"#
let regex = try Regex(pattern)

使用NSRegularExpression的不足:

  1. 正则表达式字符串需要过滤正则表达式规则符号,比如/

  2. 正则表达式是否合规只能在运行时检测创建时是否有异常抛出

现在,可以直接使用正则表达式创建一个Regex,并且在编译期就可以校验正则表达式是否合规。

let regex = /(\w+)\s+(\d+)/

针对输入字符串可以提取单词和数字组合。

let input = "Tom 123 xyz"
if let result = input.firstMatch(of: regex) {
  print(result.0)  // Tom 123  
  print(result.1)  // Tom  
  print(result.2)  // 123
  }

正则表达式提取的结果存储在一个子串数组,0下标的第一个元素是匹配到的所有内容,第一个匹配内容存储在1下标元素中,以此类推。

在提取多个元素时,可以通过读取匹配结果的output属性来获取匹配的tuple元组:

if let match = input.firstMatch(of: regex) {
  let (matched, name, count) = match.output
}

可以对待提取的元组属性进行命名:

let regex = /(?<name>\w+)\s+(?<count>\d+)/
if let match = input.firstMatch(of: regex) {  
    print(match.name)   // Tom  
    print(match.count)  // 123
}

在编写多行正则表达式时,我们也可以使用#...#来包裹正则表达式字符串,从而使得正则表达式有更好的可读性。

let regex = #/(?<name> \w+) \s+
  (?<count> \d+)/#

对正则表达式查找结果可以有不同的方式方式:

input.firstMatch(of: regex)
input.wholeMatch(of: regex)
input.prefixMatch(of: regex)

使用Regex还可以进行文本的替换,剪裁或者分割:

let line = "Tom   1234"
let line1 = line.replacing(/\s+/,with:",")  // Tom,1234let 
line2 = line.trimmingPrefix(/\w+\s+/)   // 1234
let fields = line.split(separator: /\s+/)   // ["Tom","1234"]

Regex Builder

Swift 5.7中对正则表达式的更新,除了引入Regex类方便正则表达式的使用,还设计了一个更强大的DSL构建工具:Regex Builder。传统的正则表达式大家很难掌握正则表达式的各种规则,尤其是对匹配元素的条件和组合。但在Regex Builder中,允许你用结构化,更接近自然语义的方式来构造正则表达式。以上面 /(\w+)\s+(\d+)/的正则表达式为例,在Regex Builder中可以通过下面的语句进行组装:

import RegexBuilder
let regex = Regex { 
  Capture {   
  OneOrMore(.word) 
  }
  OneOrMore(.whitespace)
  Capture {
      OneOrMore(.digit)  
  }
}
let input = "Tom 123 xyz"
if let match = input.firstMatch(of: regex) {
  let name = match.1    // Tom  
  let count = match.2   // 123
}

regex的语法规则通过大括号{}来进行组装,实际上是使用Swift的语法糖将每个条件规则包装到了闭包block中,使用

One, OneOrMore, ZeroOrMore, ChoiceOf, and Optionally. 等可读性更强,更语义化的组件使得组装正则表达变得更容易,同时代码也更容易维护和理解。举个例子:

let colorRegex = Regex {
  Capture {
      ChoiceOf {
              "red"        
              "green"        
              "blue"    
      } 
   }
   ":" 
  One(.whitespace)    
  Capture(OneOrMore(.digit))  
  ZeroOrMore(.whitespace)
  Optionally(OneOrMore(.hexDigit))
 }

使用该正则表达式解析json:

let colors = [  "red: 255 FF",  "green: 0",  "blue: 128 80"]
for color in colors {
  if let match = color.wholeMatch(of: colorRegex) {
      print(match.1, match.2)  
      }
 }
// red 255
// green 0
// blue 128

除了对正则表达的组装,Regex builder还支持转换语法:

let regex = Regex {
  Capture {
      OneOrMore(.digit) 
  } transform: {    
      Int($0)  // Int?  
  }}

通过转换函数可以将结果提取转换为需要的类型,将Capture替换为TryCapture,还可以避免输出无值的可选结果:

let regex = Regex {
  TryCapture {    
      OneOrMore(.digit)  
  } transform: {    
      Int($0)  // Int  
  }
}

正则表达式匹配模式

在正式表达式在匹配的时候有个重要的模式:贪婪匹配懒惰匹配

当正则表达式中包含能接受重复的限定符时,通常的行为是匹配尽可能多的字符。这被称为贪婪匹配。如果是匹配尽可能少的字符,则称为懒惰匹配。一般正则表达式默认使用贪婪模式进行匹配。

以一个提取数字的正则表达式为例:

let regex = Regex {
  OneOrMore(.any, .eager)
  Capture(OneOrMore(.digit))
}
let line = "hello world 99 ----> 42"
if let match = line.wholeMatch(of: regex) {
  let count = match.1  // 2
}

在第一规则OneOrMore作用是,使用贪婪匹配会匹配所有字符串直到数字4,留下最后的数字2满足第二规则OneOrMore(.digit),并被捕获为结果。所以输出结果为2。

如果改变第一规则为懒惰匹配:

let regex = Regex {
  OneOrMore(.any, .reluctant)
  Capture(OneOrMore(.digit))
}
let line = "hello world 99 ----> 42"
if let match = line.wholeMatch(of: regex) {
  let count = match.1  // 42
}

则第一个规则在满足第二规则的贪婪匹配42后,会截至到4的前面空格。

要改变一个正则表达式的匹配模式可以在表达式后追加repetitionBehavior修改器:

Regex {}
.repetitionBehavior(.reluctant)

附录

推荐一个工具:https://swiftregex.com/

可以将正则表达式转换为Regex builder代码,还可以直接在线测试效果

相关文章

网友评论

    本文标题:Swift 正则Regex

    本文链接:https://www.haomeiwen.com/subject/impjwdtx.html