🧨

正規表現と友達になろう

2023/08/29に公開

概要と用語および文法

正規表現はシンプルで美しい

  • 正規表現はシンプル, 複雑ではない

    • 正規表現の正規とは「性質のよい」や「扱いやすい」という意味を持つ
    • 例) 統計学の分野の正規分布
  • ところが, 巷では「正規表現は難しい」「正規表現意味わからん」と言われてしまっている

    • そんなことないよという話です
    • 正規表現は文字列を機械的に扱えるように上手く抽象化していることを伝えたい

最適限の用語の確認

  • 用語の整理
    • 正規表現マッチング
      • 与えられた正規表現にマッチするかどうかチェックすること
      • プログラミングでいうif文を考えている
    • メタ文字 (meta character)
      • 正規表現において特別な意味を持った文字
      • 都度調べれば良い
    • リテラル (literal)
      • 正規表現において特別な意味を持たない文字
    • 量指定子 (quantifier)
      • 他の正規表現の量を決める演算子
      • 都度調べれば良い

正規表現の文法 (代表的なもの)

  • 隣接 (concatenation)

    • “ab”
    • abという文字列
  • 選択 (or)

    • “A|B”
    • AかBという文字列
    • if 文の|と同じ
  • 繰り返し

    • “[AB]*” などの量指定子
    • プログラミングのfor文にあたる
    • Python3で言う “characters”*n
    • phpで言う repeat(”characters”, n) function
  • グループ化

    • (ab)
    • (ab){2}|(ac){3}のように文字をまとめることができる
  • 文字クラス (character class)

    • []に表現したい文字の範囲を入れるとその範囲に属する任意の一文字として表すことができる
  • ポイント

正規表現を書いてみる

  • マッチさせたい対象をとってくる

    スターバックスコーヒー
    ドトールコーヒー
    タリーズコーヒー
    サンマルクカフェ
    プロント
    コメダ珈琲店
    シャノアール
    カフェ・ド・クリエ
    シアトルズベストコーヒー
    
  • 共通化できる部分を考えておく

    • 文字列は「日本語のカタカナ」と「珈琲」「・」
    • 日本語のカタカナは「U+30A0-U+30FF」で正規表現では「[\u30A0-\u30FF]」
      • [range]はrangeの範囲にある任意の一文字
      • (拡張カタカナが入っていないと言う話は今は置いといてください)
    • 珈琲は「琲珈」と言うように逆にならないので一文字扱いして「(珈琲)」
    • 最後に「コーヒー」と言う文字がつきがちなので「(コーヒー)?$」
  • 対象を明確にする

    • カタカナ+コーヒーのパターン
    • 珈琲やカフェが入っているパターン
      • コーヒーは最初には来ないイメージがあるのでそこは省く
    • シャノアールやプロントといったその他のパターン
  • 書く

    • 慣れれば5分で書けます
    • 個人的見解ですが, 自分で書くことが大事なのかなと思っています
    |||(シャノアール)|(プロント)
    [\u30A0-\u30FF]+(コーヒー)$|||(シャノアール)|(プロント)
    [\u30A0-\u30FF]+(コーヒー)$|.+(珈琲).*|.*(カフェ).*|(シャノアール)|(プロント) // 珈琲〇〇はあまりみないので...
    
  • テスト

    スターバックスコーヒー
    ドトールコーヒー
    タリーズコーヒー
    サンマルクカフェ
    プロント
    コメダ珈琲店
    シャノアール
    カフェ・ド・クリエ
    シアトルズベストコーヒー
    コーヒー
    コーヒーhogehoge
    コーラ
    珈琲
    珈琲hogehoge
    
    • 出力
    1番目のマッチ
    スターバックスコーヒー
    2番目のマッチ
    ドトールコーヒー
    3番目のマッチ
    タリーズコーヒー
    4番目のマッチ
    サンマルクカフェ
    5番目のマッチ
    プロント
    6番目のマッチ
    コメダ珈琲店
    7番目のマッチ
    シャノアール
    8番目のマッチ
    カフェ・ド・クリエ
    9番目のマッチ
    シアトルズベストコーヒー
    

どうして人は正規表現を難しく感じるのか

  • 正規表現の情報をソースコードに残していない

    • 関数名やコメントに正規表現で表現した文字列の情報を残さないと読み直しになって面倒
    • PHPやJavaScriptを書く時にコメントを残すように正規表現でも残そう
  • 正規表現ではない部分で詰まっている

    • 文字コードの概念を知らない
    • 正規表現と文字コードは切っても切り離せないので別途学ぶ必要がある
  • 見た目がゴツい

    • シンプル \ne 簡単
    • 不要なものを削ぎ落としているから見た目がPHPやJavaScriptといった高級言語っぽくない
  • 正規表現を読まずにコピペして詰まっている

    • 本を読みましょう
    • 繰り返しになりますがシンプル \ne 簡単です
  • 正規表現のテストをうまく書けていない

    • 正規表現単体でテストできていない
      • 他の処理と一緒にテストしてしまっている
    • 異常系を書いていない
      • 正常系だけ書くとあとで考慮できていない文字列で痛い目を見ます
      • 異常系を書くことで対象の文字列をより厳密に考えることができます
  • 正規表現にロジックを書いてしまっている

練習問題

  • せっかくなので問題を作ってみました

    • ここまでの復習がてら解いてみて下さい
  • 以下の文字列にマッチする正規表現を書いてください

    • ただし, 「(SQL)」と言う表現を使って下さい

      MySQL
      PostgreSQL
      BigQuery
      SQLite
      
    • また, 以下の文字列にはマッチしないようにしてください

      SQ
      QL
      SQL
      SQLエスキューエル
      エスキューエルSQL
      1SQL
      SQL1
      
    • 最後に書いた正規表現で問題が起きそうな文字列があれば書いてください

参考文献

  • 新屋 良磨,鈴木 勇介,高田 謙.”正規表現技術入門 最新エンジン実装と理論的背景 (WEB+DB PRESS plus)”.2015.技術評論社.

Discussion