この記事を書くきっかけ
自分の場合,最初は00年代に当時抱えてた課題(立上げ中の新規カスタム設備が吐いてくるCSV形式のテキストログをVisualStudioもOfficeもないオフラインのWindows端末だけの現場でうまいこと解析したかった)を解決するために辿り着いた手法が正規表現を用いてのテキストファイル解析でそれから事あるごとに使ってきてるのですが,最近改めて正規表現って何?って聞かれることがあってそういや知らない人にうまく説明する言葉を持ってないなと気がついた次第。
さて正規表現の実用的理解
Wikipedia記事の冒頭には
文字列の集合を一つの文字列で表現する方法の一つである。
とあります。
けどここだけ読んでも何が出来るのかよく分からないと思います。
ただ,普段何気なく読んでるログやドキュメントに何か繰り返しで出てくる言葉のパターンを感じることはありませんか。
ログであればIDのカラムには「アルファベット3文字+数字4桁」の組合せ,日付のカラムには「数字4桁-数字2桁-数字2桁」という並び,レポートであれば「部門名+課名」の組合せ等々無意識でもこういったパターンを見たことあるという記憶はあると思います。
正規表現とは,こういった「アルファベット3文字+数字4桁」というようなパターンを表現するためのルールを定めたモノ,と理解して実用的には問題無さそうに思っています。
簡単な正規表現の例
先の「アルファベット3文字+数字4桁」を正規表現で表すと
[A-Za-z]{3}[0-9]{4}
となります。この時点でピンと来る人がいるかもしれません。
同様に「数字4桁-数字2桁-数字2桁」は
[0-9]{4}-[0-9]{2}-[0-9]{2}
です。
記号が多くて最初は目がチカチカするかもしれませんが少し辛抱いただくとして,勘の良い方はお気づきの通り,
- ブラケット([])は文字列集合の中の任意の一文字
- ブラケット内のハイフン(-)は範囲
- ブレース({})は繰り返しの回数
というような意味があって,以下のように解釈されます。
[A-Za-z]
# これはA〜Z(*)までの集合の中からどれか一文字(=アルファベット)を意味します
# *大文字小文字があるのでA-Za-zと書く
[A-Za-z]{3}
# このように直前の文字の繰返し回数3をつなげるとアルファベット3文字と解釈されます
# IDX のような文字列がマッチします
[0-9]
# これはお分かりの通り0から9のどれかひとつ=数字を意味します
[A-Za-z]{3}[0-9]{4}
# これらより最初のこの例は IDX0022 のような文字列がマッチします
[AUOEI]
# ちなみにこれはA,U,O,E,Iの中のどれか一文字という意味の正規表現です。
また,日付の例のように正規表現には固定文字列を混ぜられます。
[0-9]{4}-[0-9]{2}
# これは数字4桁の後ろにハイフンがひとつ,その後ろに数字2桁という意味になります
# 2022-01 がマッチします
ね,簡単でしょ?
こんな感じで正規表現を使うとあらゆる文字列と数字の組合せはもちろん,記号を使って長大なHTMLファイルの中から特定のタグの行だけ抽出,のような使い方も出来るようになります。*要センス(笑)
実装するとどんな感じ
ここではみんな大好きpythonでの実装例で雰囲気をお伝えできたらなと思います。
早速ですが実装例がこちら。
import re
# fileは文字列リストオブジェクトの想定
for row in file:
if re.search(r'<[Hh][1-6]>.*</[Hh][1-6]>', row):
# このブロックにやりたい処理を書く
pass
pythonの構文について詳細は省きますが,reモジュールのsearchメソッドは第一引数に正規表現パターン,第二引数に対象文字列を渡すとパターンマッチ結果をbool値で返すので,結果をif文で直接判定しています。
この例では<H1>...</H1>
のような見出しタグで,H1からH6すべてを対象としてマッチングします。
また,表記ゆれも考慮してH1でもh1でも検出できます。
実装例の正規表現に「.」というのがありますが,これも正規表現の一種です。
「.」はいわゆるワイルドカードで任意の一文字を表します。
「」は直前の文字の0回以上の繰り返し,という意味になります。
「.*」の組合せになると"長さ0以上の任意の文字列"ということになりそこに文字列があっても無くてもマッチングするので今回のようにタグ以外は何でも良いという場面で超使います
HTMLに関しては各種言語にそれぞれ優秀なパーサーモジュールが標準で存在するのでこのコードがそのまま使われる場面はまず無いとは思いますが,このような時正規表現を使わずに実装するとどうなるか考えると使いどころのヒントになるのではないかと思います。
最後に
実は,正規表現を使った実装の面白さ,ありがたみは後方参照による強力な置換機能やグルーピングでのキーワード抽出にあると思っていますが,本稿の趣旨と大きく逸れそうだったので割愛しました。
また,本稿では基本正規表現に準じた内容に限定していますが,これを拡張した拡張正規表現というのもあってもっと便利な記法が用意されていたりします。
これらについては調べるととんでもない量のドキュメントが見つかると思いますので興味のある方は探してみるのも良いかもしれません。