Swift Regexの話

1.2K Views

June 27, 22

スライド概要

YUMEMI.swift #15 〜WWDC復習会〜 - YouTube
https://www.youtube.com/watch?v=evzAzkcIX6Y&t=732s

YUMEMI.swift #15 〜WWDC復習会〜
https://yumemi.connpass.com/event/248135/

Swift Regexの話をしました #yumemi_swift - usami-kの日記
https://usami-k.hatenablog.com/entry/2022/06/28/000646

profile-image

https://usami-k.github.io/

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

の話 Swift Regex 宇佐見公輔 / 株式会社ゆめみ

2.

自己紹介 宇佐見公輔 / 株式会社ゆめみ iOSDC Japan 2022で記事(x2)を書き、トークをします。

3.

Swift Regex Swift 5.7で、正規表現を扱う `Regex` 型が追加される。 従来もFoundationに `NSRegularExpression` が存在した。 新しい `Regex` はSwiftの標準ライブラリとして組み込まれる。

5.

の状況 Swift Regex 現在のSwift 5.7はベータ版であり、未実装の機能がある。 セッションやドキュメントのコードが動くとは限らない。 GitHubリポジトリ apple/swift-experimental-string-processing リポジトリで開発。 その後 apple/swift リポジトリにマージ。

6.

型 Regex let regex = try Regex(#"\d+"#) // 補足: #"〜"# はSwiftの文字列リテラルの記法 "123".firstMatch(of: regex) // -> ["123"] "a12b3".firstMatch(of: regex) // -> ["12"]

7.

の生成方法 Regex let regex = try Regex(#"\d+"#) // Regex リテラル let regex = /\d+/ // Regex ビルダー import RegexBuilder let regex = OneOrMore(.digit)

8.

リテラル Regex 通常の区切り文字 // let regex = /[a-zA-Z][a-zA-Z0-9]*/ 拡張区切り文字 // let regex = #//usr/lib/.*/# 複数行リテラル // let regex = #/ \d{2} / \d{2} / \d{4} \P{currencySymbol}+ \p{currencySymbol} /# 不正な正規表現ならばビルドエラーになる。 シンタックスハイライトもサポートされる。

9.
[beta]
リテラルによる値のキャプチャ
//

キャプチャ

let regex = /user_id:\s*(\d+)/
let match = "user_id: 1234".wholeMatch(of: regex)
if let match {
print(match.0) // -> "user_id: 1234"
print(match.1) // -> "1234"
}

名前付きキャプチャ

//
let regex = /user_id:\s*(?<id>\d+)/
let match = "user_id: 1234".wholeMatch(of: regex)
if let match {
print(match.id) // -> "1234"
}

10.

の正規表現シンタックス Swift Regex 正規表現は環境によって細かいシンタックスの差異がある。 SE-0355 Regex syntax ベースの文法 : PCRE 2 / Oniguruma / ICU / .NET Unicodeをサポートする。

11.

ビルダー Regex import RegexBuilder //let regex = /\d+/ let regex = OneOrMore(.digit) let regex = Regex { OneOrMore(.digit) } //let regex = /user_id:\s*\d+/ let regex = Regex { "user_id:" ZeroOrMore(.whitespace) OneOrMore(.digit) }

12.
[beta]
ビルダーの中でリテラルを使う
import RegexBuilder
let regex = Regex {
"Test Suite '"
/[a-zA-Z][a-zA-Z0-9]*/
"' "
ChoiceOf {
"started"
"passed"
"failed"
}
" at "
OneOrMore(.any, .reluctant)
Optionally(".")
}

13.
[beta]
ビルダーによる値のキャプチャ
//let regex = /user_id:\s*(\d+)/
let regex = Regex {
"user_id:"
ZeroOrMore(.whitespace)
Capture(OneOrMore(.digit))
}
let match = "user_id: 1234".wholeMatch(of: regex)
if let match {
print(match.0) // -> "user_id: 1234"
print(match.1) // -> "1234"
}

14.
[beta]
TryCapture
let regex = Regex {
"user_id:"
ZeroOrMore(.whitespace)
TryCapture {
OneOrMore(.digit)
} transform: {
Int($0)
}
}
let match = "user_id: 1234".wholeMatch(of: regex)
if let match {
let (wholeMatch, id) = match.output
print(id) // -> 1234
}

15.

を使う Regex

16.

Regex-powered algorithms 文字列処理にRegexサポートが追加される。 input.firstMatch(of: regex) input.wholeMatch(of: regex) input.prefixMatch(of: regex) input.starts(with: regex) input.replacing(regex, with: "456") input.trimmingPrefix(regex) input.split(by: /\s*,\s*/)

17.

文のサポート switch switch "abc" { case /\w+/: print("It's a word!") } ただし、現状では未実装の様子。 (あまり分かってない。動いた人がいたら教えてください)

18.
[beta]
Regex support in Foundation
Foundationの既存のパーサーを流用できる。
import Foundation
let regex = Regex {
One(.date(.numeric,
locale: Locale(identifier: "ja_JP"),
timeZone: TimeZone.current))
}
"2022/06/27".starts(with: regex) // -> true

19.
[beta]
カスタムのパーサーを使う
import Darwin
struct CDoubleParser: CustomConsumingRegexComponent {
typealias RegexOutput = Double
func consuming(
_ input: String,
startingAt index: String.Index,
in bounds: Range<String.Index>
) throws -> (upperBound: String.Index, output: Double)? {
// ...
}
}
let regex = Regex {
CDoubleParser()
}

20.

まとめ Swift Regex `Regex` 型 Regexリテラル / Regexビルダー Regex-powered algorithms / Regex support in Foundation