NSRegExNamedCaptureGroup 1.0.0

NSRegExNamedCaptureGroup 1.0.0

测试已测试
Lang语言 SwiftSwift
许可证 自定义
发布最后发布2017年7月
SwiftSwift 版本3.0
SPM支持 SPM

Torin Kwok 维护。



  • Torin Kwok 编写

我们面临的问题

几乎所有现代正则表达式引擎都支持编号捕获组和编号回溯引用。具有大量组和回溯引用的长正则表达式可能难以阅读。它们在维护方面尤其困难,因为在中部添加或删除捕获组可能会打乱之后所有组的编号。

好消息

Python、PHP 的 preg 引擎和 .NET 语言等语言或库支持捕获到命名的位置,我们称之为“命名捕获组”。命名捕获组(NCG)的一个最重要的好处是为每个单独的捕获组分配一个人类可读的名称,可能会使阅读源码的人感到不那么困惑,否则他们可能不知道哪一个数字与哪个捕获组相对应。

坏消息

命名捕获组很棒。 NSRegularExpression 不支持它。

你在开玩笑吗?

Cocoa 的 NSRegEx 实现根据苹果官方文档,是基于 ICU 的正则表达式实现

当前支持的模式语法是 ICU 规定的。ICU 正则表达式描述在 http://userguide.icu-project.org/strings/regexp

该页面(在 http://http://site.icu-project.org)声称现在支持命名捕获组,使用与 .NET 正则表达式相同的语法

(?...) 命名捕获组。它们是文字的 - 它们出现在模式中。

例如

\b**(?\d\d\d)-(?\d\d\d)-(?**\d\d\d\d)\b

然而,苹果官方对 NSRegEx 的文档没有列出命名捕获组的语法,它只在 ICU 的文档中列出,这表明NCG是一个新增功能,因此Cocoa的实现尚未集成。

也就是说,目前通过 NSRegEx 暴露的捕获组匹配结果的唯一方法是通过在 NSTextCheckingResult 类中调用 rangeAt(:_) 方法进行数字化的。冷静下来,Cocoa。

那些流泪的人是有福的... - 马太福音5:4

扩展库,NSRegExNamedCaptureGroup,旨在为使用NSRegEx的开发者提供一个直观的方式来处理正则表达式中的命名捕获组。

安装

Carthage:

如果您使用Carthage来管理依赖项

  1. 只需将NSRegExNamedCaptureGroup添加到您的Cartfile
github "TorinKwok/NSRegExNamedCaptureGroup" ~> 1.0.0
  1. 单击Xcode菜单栏中的文件 -> 将文件添加到 "$PROJECT_NAME"项。选择NSRegExNamedCaptureGroup.xcodeproj

  2. NSRegExNamedCaptureGroup嵌入到通用面板

CocoaPods:

要使用CocoaPods安装,将以下内容添加到您的项目Podfile中

pod 'NSRegExNamedCaptureGroup', '~>1.0.0'

Swift包管理器:

Swift包管理器是一个用于管理Swift代码分发工具。它与Swift构建系统集成,以自动下载、编译和链接依赖项的过程。

一旦您设置好Swift包,将框架添加为依赖项就像将其添加到您的Package.swift的依赖项值一样简单。

dependencies: [
    .Package( url: "https://github.com/TorinKwok/NSRegExNamedCaptureGroup.git", majorVersion: 1 )
  ]

Git子模块:

  1. 使用git submodule命令将此仓库克隆到您的项目中
git submodule add https://github.com/TorinKwok/NSRegExNamedCaptureGroup.git "$SRC_ROOT" --recursive`
  1. 剩余步骤与Carthage部分中的最后两个步骤相同

用法

import NSRegExNamedCaptureGroup

let phoneNumber = "202-555-0136"

// Regex with Named Capture Group.
// Without importing NSRegExNamedCaptureGroup, you'd have to 
// deal with the matching results (instances of NSTextCheckingResult)
// through passing the Numberd Capture Group API: 
// `rangeAt(:_)` a series of magic numbers: 0, 1, 2, 3 ...
// That's rather inconvenient, confusing, and, as a result, error prune.
let pattern = "(?<Area>\\d\\d\\d)-(?:\\d\\d\\d)-(?<Num>\\d\\d\\d\\d)"

let pattern = try! NSRegularExpression( pattern: pattern, options: [] )
let range = NSMakeRange( 0, phoneNumber.utf16.count )

使用NSRegEx的第一次匹配便利方法

let firstMatch = pattern.firstMatch( in: phoneNumber, range: range )

// Much better ... 

// ... than invoking `rangeAt( 1 )`
print( NSStringFromRange( firstMatch!.rangeWith( "Area" ) ) )
// prints "{0, 3}"

// ... than putting your program at the risk of getting an
// unexpected result back by passing `rangeAt( 2 )` when you
// forget that the middle capture group (?:\d\d\d) is wrapped 
// within a pair of grouping-only parentheses, which means 
// it will not participate in capturing at all.
//
// Conversely, in the case of using
// NSRegExNamedCaptureGroup's extension method `rangeWith(:_)`,
// we will only get a range {NSNotFound, 0} when the specified
// group name does not exist in the original regex.
print( NSStringFromRange( firstMatch!.rangeWith( "Exch" ) ) )
// There's no a capture group named as "Exch",
// so prints "{9223372036854775807, 0}"

// ... than invoking `rangeAt( 2 )`
print( NSStringFromRange( firstMatch!.rangeWith( "Num" ) ) )
// prints "{8, 4}"

使用基于阻塞枚举的NSRegEx API

pattern.enumerateMatches( in: phoneNumber, range: range ) {
  match, _, stopToken in
  guard let match = match else {
    stopToken.pointee = ObjCBool( true )
    return
    }

  print( NSStringFromRange( match.rangeWith( "Area" ) ) )
  // prints "{0, 3}"

  print( NSStringFromRange( match.rangeWith( "Exch" ) ) )
  // There's no a capture group named as "Exch"
  // prints "{9223372036854775807, 0}"

  print( NSStringFromRange( match.rangeWith( "Num" ) ) )
  // prints "{8, 4}"
  }

使用基于数组的NSRegEx API

let matches = pattern.matches( in: phoneNumber, range: range )
for match in matches {
  print( NSStringFromRange( match.rangeWith( "Area" ) ) )
  // prints "{0, 3}"

  print( NSStringFromRange( match.rangeWith( "Exch" ) ) )
  // There's no a capture group named as "Exch"
  // prints "{9223372036854775807, 0}"

  print( NSStringFromRange( match.rangeWith( "Num" ) ) )
  // prints "{8, 4}"
  }

要求

  • macOS 10.10+ / iOS 8.0+ / tvOS 9.0+ / watchOS 2.0+
  • Xcode 8.1, 8.2, 8.3和9.0
  • Swift 3.0, 3.1, 3.2和4.0

作者

Torin Kwok 编写.

许可

Apache-2.0.