Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Meet Swift Regex

Meet Swift Regex

Meet Swift Regex : WWDC22セッション要約

登壇
https://www.youtube.com/watch?v=IpQAovAzwf8&t=3980s

集まれSwift好き!Swift愛好会スピンオフ WWDC22セッション要約会 @オンライン
https://love-swift.connpass.com/event/247317/

USAMI Kosuke

June 24, 2022
Tweet

More Decks by USAMI Kosuke

Other Decks in Programming

Transcript

  1. Meet Swift Regex
    WWDC22
    セッション要約
    宇佐見公輔
    /
    株式会社ゆめみ

    View full-size slide

  2. 自己紹介
    宇佐見公輔 /
    株式会社ゆめみ
    iOSDC Japan 2022
    で記事(x2
    )を書き、トークをします。
    来週6/27
    (月)にも、YUMEMI.swift #15
    でSwift Regex
    の話をします。

    View full-size slide

  3. Meet Swift Regex
    Swift 5.7
    で、正規表現を扱う Regex
    型が追加される。
    注意:セッション中のコードはビルドできないものがいくつかある。
    ` `

    View full-size slide

  4. Scenario: Financial investigation
    以下のような文字列データ(金融取引の記録)を処理したい。
    取引の種類、取引日、個人または機関名、金額
    各フィールドは2
    つ以上のスペースまたはタブで区切られる。
    KIND DATE INSTITUTION AMOUNT

    ----------------------------------------------------------------

    CREDIT 03/01/2022 Payroll from employer $200.23

    CREDIT 03/03/2022 Suspect A $2,000,000.00

    DEBIT 03/03/2022 Ted's Pet Rock Sanctuary $2,000,000.00

    DEBIT 03/05/2022 Doug's Dugout Dogs $33.27

    View full-size slide

  5. Processing collections
    split
    で分割してはどうか。
    ["Doug\'s", "Dugout", "Dogs"]
    は意図しない分割。
    「2
    つ以上のスペースまたはタブ」で区切りたい。
    そこで正規表現を使う。
    ` `
    let transaction = "DEBIT 03/05/2022 Doug's Dugout Dogs $33.27"

    let fragments = transaction.split(whereSeparator: \.isWhitespace)

    // ["DEBIT", "03/05/2022", "Doug\'s", "Dugout", "Dogs", "$33.27"]
    ` `

    View full-size slide

  6. Processing strings
    Regex
    リテラルが使える split(by:)
    が追加された。
    ` `
    let transaction = "DEBIT 03/05/2022 Doug's Dugout Dogs $33.27"

    let fragments = transaction.split(by: /\s{2,}|\t/)

    // ["DEBIT", "03/05/2022", "Doug's Dugout Dogs", "$33.27"]

    View full-size slide

  7. struct Regex
    Regex
    の生成方法は以下がある。
    Regex literals
    Runtime construction
    Regex builders

    View full-size slide

  8. struct Regex
    // Regex
    リテラル

    let digits = /\d+/
    //
    実行時に生成

    let runtimeString = #"\d+"# //
    補足 : #"
    〜"#
    はSwift
    の文字列リテラルの一種

    let digits = try Regex(runtimeString)

    // Regex
    ビルダー

    import RegexBuilder

    let digits = OneOrMore(.digit)

    View full-size slide

  9. Swift Regex
    以下の4
    つの強みがある。
    簡明なリテラルと構造的なビルダーが使える。
    正規表現の一部に既存のパーサーが使える。
    Unicode
    を扱える。
    Predictable execution, prominent controls

    View full-size slide

  10. Create a Regex builder
    import RegexBuilder

    import Foundation

    let fieldSeparator = /\s{2,}|\t/

    let transactionMatcher = Regex {

    /CREDIT|DEBIT/

    fieldSeparator

    One(.date(.numeric, locale: Locale(identifier: "en_US"), timeZone: .gmt))

    fieldSeparator

    OneOrMore {

    NegativeLookahead { fieldSeparator }

    CharacterClass.any

    }

    fieldSeparator

    One(.localizedCurrency(code: "USD").locale(Locale(identifier: "en_US")))

    }

    View full-size slide

  11. Capture
    let transactionMatcher = Regex {

    Capture { /CREDIT|DEBIT/ }

    fieldSeparator

    Capture { One(.date(.numeric, locale: Locale(identifier: "en_US"), timeZone: .gmt
    fieldSeparator

    Capture {

    OneOrMore {

    NegativeLookahead { fieldSeparator }

    CharacterClass.any

    }

    }

    fieldSeparator

    Capture { One(.localizedCurrency(code: "USD").locale(Locale(identifier: "en_US"))
    }

    View full-size slide

  12. Capture
    Capture
    した部分は、次のように取り出せる。
    let transaction = "DEBIT 03/05/2022 Doug's Dugout Dogs $33.27"

    let match = transaction.wholeMatch(of: transactionMatcher) {

    let (kind, date, institution, amount) = match.output

    // ...

    }

    View full-size slide

  13. Plot twist
    金額の単位に応じて、日付部分のパース処理を変えたい。
    金額が $
    の場合は month/day/year
    とみなす。
    金額が £
    の場合は day/month/year
    とみなす。
    DEBIT 03/05/2022 Doug's Dugout Dogs $33.27

    DEBIT 06/03/2022 Oxford Comma Supply Ltd. £57.33
    ` ` ` `
    ` ` ` `

    View full-size slide

  14. Plot twist
    Foundation
    の Date
    パース時のstrategy
    機能を活用する。
    ` `
    func pickStrategy(_ currency: Substring) -> Date.ParseStrategy {

    switch currency {

    case "$":

    return .date(.numeric, locale: Locale(identifier: "en_US"), timeZone: .gmt)

    case "£":

    return .date(.numeric, locale: Locale(identifier: "en_GB"), timeZone: .gmt)

    default: fatalError("We found another one!")

    }

    }

    View full-size slide

  15. Plot twist
    let regex = #/

    (? \d{2} / \d{2} / \d{4})

    (? \P{currencySymbol}+)

    (? \p{currencySymbol})

    /#

    ledger.replace(regex) { match -> String in

    let date = try! Date(String(match.date), strategy: pickStrategy(match.currency))

    let newDate = date.formatted(.iso8601.year().month().day())

    return newDate + match.middle + match.currency

    }

    View full-size slide

  16. Unicode
    switch ("
    🧟‍♀️💖🧠", "The Brain Cafe\u{301}") {

    case (/.\N{SPARKLING HEART}./, /.*café/.ignoresCase()):

    print("Oh no!
    🧟‍♀️💖🧠, but
    🧠💖☕️
    !")

    default:

    print("No conflicts found")

    }

    View full-size slide

  17. TryCapture
    TryCapture
    でCapture
    したデータを変換できる。
    let fieldSeparator = /\s{2,}|\t/

    let field = OneOrMore {

    NegativeLookahead { fieldSeparator }

    CharacterClass.any

    }

    let transactionMatcher = Regex {

    Capture { /CREDIT|DEBIT/ }

    fieldSeparator

    TryCapture(field) { timestamp ~= $0 ? $0 : nil }

    fieldSeparator

    TryCapture(field) { details ~= $0 ? $0 : nil }

    fieldSeparator

    // ...

    }

    View full-size slide

  18. Local
    上述の正規表現は、セパレータの処理に無駄がある。 例えば、8
    つの空白を
    見つけた場合、次のようになる(グローバルバックトラッキング)。
    8
    つの空白の残りが正規表現にマッチするか調べる。
    マッチしなければ、次に7
    つの空白の残りがマッチするか調べる。
    マッチしなければ、次に6
    つの空白の残りがマッチするか調べる。
    これを避けるため、 Local
    を使うことができる。
    ` `
    let fieldSeparator = Local { /\s{2,}|\t/ }

    View full-size slide

  19. 次に見るセッション
    より詳しくは「Swift Regex: Beyond the basics
    」のセッションを見よ。

    View full-size slide