Slide 1

Slide 1 text

Swift 5.7で変わる正規表現を試してみよう ainame (Satoshi Namai) - iOSDC 2022

Slide 2

Slide 2 text

自己紹介 @ainame / 生井智司/ Satoshi Namai ● Senior iOS Engineer at Cookpad Ltd*1 ● イギリス地方都市ブリストル在住 ● リモート参加 *1 https://careers.cookpad.com/

Slide 3

Slide 3 text

https://cookpad.connpass.com/event/254459/ enum で Key Paths のような機能を実 現する Case Paths by アイカワ Maintainability Indexを計測することで iOSプロジェクトのコードの保守性を改善し た話 by toya108 DocC Documentation Archiveをアプ リ開発で活用してみよう by あおい OpenAPIのクライアント自動生成を現場に導 入していくためのノウハウ by imajin

Slide 4

Slide 4 text

今日話すこと ● 新しい正規表現を試す方法 ● これまでのSwiftでの正規表現 ● 正規表現リテラル / Regex Builder ● swift-evoltuionから読み解く推しポイント ● パフォーマンスについて *正規表現そのものに関してはある程度  知っている前提で話します

Slide 5

Slide 5 text

新しい正規表現を試す方法 Swift 5.7が必要で開発中のバージョンはXcode 14 betaで 既に利用可能で今年秋頃に正式版とともにリリースされる見込み 主な変更点 ● if let の導入 / 型推論の改善 ● Genericsの改善 ● Distoributed Actorの導入 ● 正規表現リテラル+Regex Builderによる文字列処理 https://www.swift.org/blog/swift-language-updates-from-wwdc22/

Slide 6

Slide 6 text

新しい正規表現を試す方法 ● Xcode 14 (beta)を使う ○ Playgroundが楽 ○ macOSがVenturaでなければiOS環境で試す ■ RegexはmacOS 13から、iOS 16から利用できる ● オンライン上で試す ○ @k_katsumiさん製 https://swiftregex.com/

Slide 7

Slide 7 text

これまでのSwiftの正規表現 ● Swiftではこれまでも正規表現は利用できた ○ NSRegularExpression ○ NSString由来のメソッド ■ range(of:,options:,range:,locale) ■ replacingOccurrences(of:,with:,options:,range:) ● 使いづらい(個人の感想) ○ NSString由来のメソッドは用途が限られている ○ SwiftのStringのようなUnicodeの挙動が無い

Slide 8

Slide 8 text

https://www.hackingwithswift.com/example-code/strings/nsregularexpression-how-to-match-regular-expressions-in-strings より引用して一部修正

Slide 9

Slide 9 text

←まずtryを使わないと インスタンスを作れない。 サクッと実行したいだけなのに 失敗時のことも考える必要がある https://www.hackingwithswift.com/example-code/strings/nsregularexpression-how-to-match-regular-expressions-in-strings より引用して一部修正

Slide 10

Slide 10 text

← #"My name is (\w*)"# と書けば 二重でエスケープせずに済むが いちいち考えさせられる https://www.hackingwithswift.com/example-code/strings/nsregularexpression-how-to-match-regular-expressions-in-strings より引用して一部修正

Slide 11

Slide 11 text

https://www.hackingwithswift.com/example-code/strings/nsregularexpression-how-to-match-regular-expressions-in-strings より引用して一部修正 ↓ 実行にNSRangeが必要

Slide 12

Slide 12 text

https://www.hackingwithswift.com/example-code/strings/nsregularexpression-how-to-match-regular-expressions-in-strings より引用して一部修正 ←キャプチャ結果を取り出す  のにNSRangeの変換と  Optional bindingが必要

Slide 13

Slide 13 text

正規表現リテラル - Regex Literals ✅ 正規表現リテラル ℹ 動的にパターンを組み立てることも可(tryが必要)

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

←正規表現リテラルなので  コンパイル時に  シンタックスエラーが  分かるためtryが不要

Slide 16

Slide 16 text

← 名前付きキャプチャの場合はキーで アクセスできる

Slide 17

Slide 17 text

← そうでない場合はタプルの要素の   順序の数字でアクセスできる

Slide 18

Slide 18 text

← RegexとStringどちらから でもマッチングできる

Slide 19

Slide 19 text

← 複数件のマッチを調べる のはStringがレシーバー になる必要がある

Slide 20

Slide 20 text

← 新たに追加された正規表現を使った 文字列処理のためのメソッド

Slide 21

Slide 21 text

Regex Builder “I had a problem so I wrote a regular expression. Now I have two problems.” 正規表現は問題解決に便利だが構文が複雑なので長期的にメ ンテナンスするのが難しい Regex Builderは正規表現の問題点を解決するために導入され たDSL

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

↑日時、漢数字、単語、 URLが 混じった文字列のパース処理を考える

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

← Regex BuilderによるDSL Result Builderで実装され  ているのでSwiftUIのよう  記述する

Slide 26

Slide 26 text

↓ OneOrMore(.word) == “\w+” One(.whitespace) == “\s”

Slide 27

Slide 27 text

←正規表現リテラルも組み込める

Slide 28

Slide 28 text

日時、URLなどよく現れるフォーマット はFoundationにパーサーが実装されてる

Slide 29

Slide 29 text

←日本語の漢数字のFormatter ↓transformクロージャで漢数字の StringをIntに変換

Slide 30

Slide 30 text

←単なるSubstringだけでなくそれぞれ  Date, Int, URLとなっている ←各Captureに対して渡すことで  名前付きキャプチャの値のアクセス  のために使え、値の型も宣言できる

Slide 31

Slide 31 text

正規表現リテラル vs Regex builder ● リテラルは簡潔に書けるのがメリット ○ シンプルなパターンを使う時に向いている ● Regex builderは構造化出来る ○ 可読性を上げるためコンポーネント化が可能 ○ Capture時に任意の型でパースした結果を取り出せる ○ 正規表現リテラルも組み込める ○ コードの補完があるので書きやすい ● 適材適所 ● XcodeでリテラルをRegex Builder変換できる

Slide 32

Slide 32 text

Xcodeの正規表現リテラルからRegexBuilderへの変換

Slide 33

Slide 33 text

swift-evolution swift-evolutionでは6つの提案が承認されている ● SE-0350 Regex Type and Overview ● SE-0351 Regex builder DSL ● SE-0354 Regex Literals ● SE-0355 Regex Syntax and Run-time Construction ● SE-0357 Regex-powered string processing algorithms ● SE-0363 Unicode for String Processing

Slide 34

Slide 34 text

swift-evolutionから読み解く推しポイント 既存の文字列処理の問題点を解決のため作られているため他 言語には珍しい仕様が盛り込まれている ● メジャーな正規表現の方言・機能をカバー ● 正規表現リテラルのコンパイル時文法チェック ● Unicodeの仕様に準拠した正確な文字列比較

Slide 35

Slide 35 text

メジャーな正規表現の方言・機能をカバー ● 正規表現エンジンの仕様や実装はいろいろある ● 他の言語で動作するパターンが使えないと悲しい ● Swiftの正規表現エンジンでは以下に対応 ○ PCRE 2 - “業界標準” Perlの仕様がベース ○ Oniguruma - Rubyに一度導入され様々な機能が追加された ○ ICU - NSReguarExpressionで使われている ○ .NET - ユニークな機能が追加されている

Slide 36

Slide 36 text

コンパイル時文法チェック 正規表現が言語のコア=コンパイラーにも組み込まれている ためコンパイル時にシンタックスエラーをチェックできる * Xcodeを使えば普通のシンタックスエラーと同様にバックグラウンドで解 析してくれる

Slide 37

Slide 37 text

Unicodeの仕様に準拠した正確な文字列比較 ● Unicodeには正規表現の実装のガイドライン*1が存在 ○ Basic Unicode Support: Level 1 ○ Extended Unicode Support: Level 2 ○ Tailored Support: Level 3 (撤回済み) ● Swift 5.7はLevel1とLevel 2のうちの重要な仕様を実装 ○ Canonical Equivalents ○ Extended Grapheme Clusters and Character Classes with Strings ○ Default Word Boundaries *1 Unicode® Technical Standard #18 https://unicode.org/reports/tr18/

Slide 38

Slide 38 text

Canonical Equivalents 異なるUnicodeの表現でも見た目上等価なら同じと見なす =正準等価(Canonical Equivalents)

Slide 39

Slide 39 text

パフォーマンス ● 実行速度は重要(速ければ速いほどいい) ○ 特にサーバーサイドアプリケーションや データの解析などに使う場合は重要 ● 2つのベンチマークの結果をみていく ○ マイクロベンチマーク: RegexBenchmark ○ リアルワールドのタスク: xcbeautify

Slide 40

Slide 40 text

RegexBenchmark ● Swift 5.7の正規表現の開発に利用されている apple/swift-experimental-string-processingに付属する公 式のベンチマーク ● 以下の環境で実行 ○ Branch: swift/release/5.7 (3c9a2e) ○ Snapshot: swift-5.7-DEVELOPMENT-SNAPSHOT-2022-08-02-a ○ MacBook Pro 16inch (2021) / CPU: M1 Max / Memory: 64GB

Slide 41

Slide 41 text

1,647.37 NSRegularExpressionの実行時間を1とした時の Swift 5.7 Regexの各ベンチマークの実行時間 値が低いほど良い

Slide 42

Slide 42 text

xcbeautify ● CIでよく使われるSwift製のxcodebuildのログフォーマッター ● 内部に正規表現のパターンがいっぱい定義されている ● 現状NSRegularExpressionが利用されているがRegexの実装を切り替 えるためのブランチが存在

Slide 43

Slide 43 text

xcbeautify ● OSSのmozilla/focus-iosのxcodebuildのログを保存してパース ● tuist/xcbeautifyのinject-matchingブランチと forkしたブランチ*1で各releaseモードでビルドし比較 *1 https://github.com/ainame/xcbeautify/commit/a59302fc60119b0829cb8cbef28bc4d7ca0f792d

Slide 44

Slide 44 text

xcbeautify ● 結果: 約8倍遅い ● あくまで保存済みのxcodebuildのログファイルに対する処 理をみた時の実行時間 ● 実際はxcodebuildがビルド処理を実行中に出力するログを 処理するためそこまで気にならないかも? 3回実行の平均 NSRegularExpression版 0.50 secs Swift 5.7 Regex版 4.04 secs

Slide 45

Slide 45 text

まとめ ● Swift 5.7の正規表現は非常に丁寧に仕様が検討されてる ○ NSRegularExpressionの使いづらさを解決した標準ライブラリ ○ ツールのサポートによる生産性の高い正規表現リテラル ○ 拡張性とメンテナンス性が高いRegex builder ○ Unicode-awareなマッチングエンジン ● パフォーマンスは今後に期待 ○ 仕様の実装が先で最適化は後なのは分かる ○ とはいえiOSアプリで入力値のバリデーション用途などで 使う分にはほとんど気にしなくて良い

Slide 46

Slide 46 text

ご清聴ありがとうございました After Party iOSDC 2022もよろしく connpassみてね