$30 off During Our Annual Pro Sale. View Details »

Swift 5.7で変わる正規表現を試してみよう

ainame
September 12, 2022

Swift 5.7で変わる正規表現を試してみよう

現在swift-evolutionでは大量のproposalと共に長年Swift上で不便だった正規表現関連の実装を刷新する流れが続いています。実際にWWDC 22でもSwift 5.7のリリースとともにRegexBuilderと正規表現リテラルが導入されることが発表されています。

このトークではNSRegularExpressionやNSStringにおける課題がどのように解決されているかをswift-evolutionの各proposalをもとに振り返り、iOSやサーバーサイドでのアプリケーションや文字列処理が生きてくる書き捨てのスクリプト(例えばログ解析など)でどれぐらい実用的に利用できるのかをベンチマーク結果を添えて検証していきます。

特に普段Rubyなどで書くことが多い書き捨てスクリプトを置き換えるポテンシャルがあるのかどうかに個人的に興味があります!!いかに!?

ainame

September 12, 2022
Tweet

More Decks by ainame

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  22. View Slide

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

    View Slide

  24. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  33. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  37. 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/

    View Slide

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

    View Slide

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

    View Slide

  40. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide