📘

SwiftでRegexを別structに切り分ける

2022/08/31に公開

Regexの合成

SwiftのRegexは合成することができます。
電話番号と住所を正規表現で確認したい場合に、1つの変数で全て宣言するのではなく、要素を分けて後で合成することも可能です。

let phoneNumberRegex = Regex {
  ...
}

let addressRegex = Regex {
  ...
}

let documentRegex = Regex {
  phoneNumberRegex
  addressRegex
}

別structに切り分ける

変数で宣言すると使いずらい部分があるため別structに切り分け宣言する方法を紹介していきます。

structをRegexComponentに準拠させて変数regexの中身を実装することで別structに切り分けることができます。

以下では電話番号の正規表現を実装しています。中身はMozillaで載っていたものを参考にしています。

struct PhoneNumberRegex: RegexComponent {
  // (?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}
  // (○)123-456-7890
  // (○)(123)-456-7890
  // (○)123.456.7890
  // (○)(123)/456/7890
  // (×)123.456/7890 区切り文字が前と後ろで異なるため
  // (×)123*456*7890 区切り文字が想定しているものではない
  // (×)1233.456.7890 最初の数字が4桁になっている

  @RegexComponentBuilder
  var regex: Regex<Regex<(Substring, Substring, Reference<Substring>.RegexOutput)>.RegexOutput> {
    let separator = Reference(Substring.self)
    ChoiceOf {
      Repeat(count: 3) {
        One(.digit)
      }
      Regex {
        "("
        Repeat(count: 3) {
          One(.digit)
        }
        ")"
      }
    }

    Capture(as: separator) { One(.anyOf("./-")) }

    Repeat(count: 3) {
      One(.digit)
    }

    Capture(separator)

    Repeat(count: 4) {
      One(.digit)
    }
  }
}
struct DocumentRegex: RegexComponent {
  @RegexComponentBuilder
  var regex: Regex<(Substring, Substring, Reference<Substring>.RegexOutput)> {
    PhoneNumberRegex()
    AddressRegex()
  }
}

Discussion