正規表現入門 - 文字列処理の強い味方
正規表現とは何かという概念から、メタ文字・文字クラス・量指定子の読み方、そして若手が陥りがちなつまずきまでを、実際に動く例とともに丁寧に解説する若手エンジニア向けの入門記事です。
ログの中から「それらしい行」だけを拾いたいとき
数万行のアクセスログから、エラーになったリクエストだけを抜き出したい。あるいは、ユーザーが入力したメールアドレスが「それらしい形」をしているか確かめたい。手作業で目視するには多すぎるし、「error という単語を含む行」という単純な検索では取りこぼしが出ます。エラーコードが E001 や E512 のように毎回違う番号だったら、検索窓に何を打てばよいのでしょうか。
こうした「形は決まっているが、中身が一つひとつ違う文字列」を相手にするとき、力を発揮するのが正規表現です。この記事では、正規表現が何のための道具なのかという考え方から始め、実際に手元で動かせる例を通して、読み書きの基礎を身につけていきます。
正規表現とは「文字列のパターン」を書く言語です
正規表現(regular expression、略して regex や regexp)とは、文字列の集合を一つの式で言い表すための小さな記法です。ポイントは、特定の文字列そのものではなく「どんな形をしているか」を書く点にあります。
たとえば「E で始まり、そのあとに数字が3つ続く文字列」というパターンを考えます。これは E001 にも E512 にも当てはまります。個別の番号を全部列挙しなくても、形さえ決めれば無数の文字列を一度に言い当てられます。ここが正規表現の本質です。
身近なたとえで言えば、正規表現は「手配書の人相書き」に似ています。「背が高くて眼鏡をかけた人」という特徴を書いておけば、名前を知らなくても該当する人を見つけられます。正規表現も同じで、「数字が3つ」「@ を含む」といった特徴を書くことで、名前(具体的な文字列)を知らないまま対象を捕まえられるわけです。
なぜこんな道具が必要なのでしょうか。プログラムが扱うデータの多くは、ログ、CSV、ユーザー入力といった「半分だけ構造がある文字列」です。完全にバラバラでもなく、かといって固定でもありません。この「ゆるい規則」を表現する手段として、正規表現は多くの言語やツールに標準で組み込まれてきました。
メタ文字 — 「特別な意味を持つ文字」を知る
正規表現を読むうえで最初の関門が、メタ文字の存在です。メタ文字とは、文字そのものではなく「特別な働き」を持つ記号のことです。たとえば .(ドット)は、正規表現の中では「ピリオドという文字」ではなく「任意の1文字」を意味します。
主要なメタ文字を、まず考え方の対応表として示します。
| 記法 | 意味 |
|---|---|
. | 任意の1文字 |
\d | 数字1文字(digit) |
\w | 英数字またはアンダースコア1文字(word) |
\s | 空白文字(space) |
^ | 行の先頭 |
$ | 行の末尾 |
\d の d は digit(数字)、\w の w は word(単語構成文字)の頭文字です。意味を丸暗記するより、由来と結びつけると忘れにくくなります。
つまずきポイント:ドットは「なんでも」当たってしまう
初心者が最初に驚くのが、. の当たりの広さです。IPアドレスを探そうとして 192.168.0.1 という正規表現を書くと、ドットが「任意の1文字」として働くため、192x168y0z1 のような文字列にも当たってしまいます。
「ドットという文字そのもの」を表したいときは、直前にバックスラッシュを置いて \. と書きます。これをエスケープと呼びます。メタ文字の特別な意味を打ち消し、ただの文字に戻す操作です。192\.168\.0\.1 と書けば、意図どおりドットの位置にはドットだけが当たります。
量指定子 — 「何回くり返すか」を指定する
次に押さえるのが、くり返しの表現です。量指定子(quantifier)とは、直前のパターンが何回くり返されるかを指定する記号です。これがあるおかげで、「数字が3つ」「1文字以上」といった長さの揺れを表せます。
| 記法 | 意味 |
|---|---|
* | 0回以上 |
+ | 1回以上 |
? | 0回または1回 |
{3} | ちょうど3回 |
{2,4} | 2回以上4回以下 |
冒頭の「E で始まり数字が3つ」は、これらを使うと E\d{3} と書けます。\d が数字1文字、{3} が「それを3回」という意味です。人相書きの特徴を、そのまま記号に翻訳した形になっています。
つまずきポイント:+ と * の取り違え
* は「0回以上」なので、1回も現れなくてもマッチが成立します。たとえば「1文字以上の数字」を表したいのに \d* と書くと、数字がまったくない空の位置にも当たってしまい、意図しない結果になります。「最低1つは欲しい」なら + を使う、と覚えておくと安全です。0回を許すかどうかは、後々のバグの分かれ目になります。
手を動かして確かめる
ここまでの記法を、実際に動かして確認します。以下は macOS や Linux に標準で入っている grep コマンドの例です。ターミナルがあれば追加インストールなしで試せます。-E は拡張正規表現を有効にするオプションです。
# Create a sample log file
printf 'E001 login failed\nINFO ok\nE512 timeout\n' > sample.log
# Extract only lines that have "E" followed by exactly 3 digits
grep -E 'E[0-9]{3}' sample.log
このコマンドを実行すると、E001 login failed と E512 timeout の2行だけが出力され、INFO ok は除外されます。E[0-9]{3} の [0-9] は「0から9のいずれか1文字」を表す文字クラスで、\d とほぼ同じ意味です。grep では環境によって \d が使えないことがあるため、確実な [0-9] を使いました。ここが「同じ正規表現でもツールごとに方言がある」という注意点でもあります。
次に、プログラミング言語での例として Python を見ます。Python 3 があれば動きます。
import re
text = "contact: [email protected], [email protected]"
# Find all strings shaped like an email address
pattern = r"[\w.]+@[\w.]+\.\w+"
print(re.findall(pattern, text))
# => ['[email protected]', '[email protected]']
r"..." は raw 文字列といい、バックスラッシュをそのまま正規表現に渡すための書き方です。パターンは「英数字かドットが1文字以上」「@」「同じく1文字以上」「\.(本物のドット)」「英数字が1文字以上」という並びで、メールアドレスの「形」を表しています。re.findall は、その形に当てはまる部分をすべてリストで返します。
なお、この式は厳密なメールアドレス検証ではありません。正規表現でメールアドレスを完全に検証しようとしない、というのはプロが共有する現実的な指針です。仕様が複雑すぎて実用的な式に収まらないため、実務では「送信して確認できるか」で担保します。正規表現は万能ではなく、適した仕事に使う道具だと捉えてください。
安全な習慣:まず「検索」で確かめてから「置換」する
正規表現は置換にも使えますが、いきなり置換を実行すると、意図より広く当たって取り返しのつかない変更をしてしまうことがあります。プロがまず行うのは、同じパターンで検索だけをして、当たる範囲を目で確認することです。エディタなら置換前に検索結果をハイライトさせる、sed なら本番前に grep で対象行を眺める。この「破壊的操作の前に確認する」一手間が、事故を防ぎます。
まとめ
正規表現の考え方を、あらためて整理します。
- 正規表現は「文字列そのもの」ではなく「文字列の形(パターン)」を書く記法です。人相書きのように、特徴で対象を捕まえます。
- メタ文字は特別な意味を持つ記号で、文字として扱いたいときは
\.のようにエスケープします。 - 量指定子は「くり返しの回数」を指定します。
*(0回以上)と+(1回以上)の違いは、バグの分かれ目です。 - 同じ正規表現でもツールごとに方言があり、正規表現は万能ではありません。適した仕事に使います。
次の一歩として、今日いちばん身近なファイルを一つ選び、grep -E で「数字が3つ以上続く行」を探す grep -E '[0-9]{3,}' を実際に打ってみてください。自分のデータで一度当ててみると、記号の意味が一気に手に馴染みます。
※ この記事はAIが自動生成したものです。本記事の内容は執筆時点の情報であり、正確性を保証するものではありません。ご利用の際は免責事項をご確認ください。
Related / 関連記事
関連記事
Comments / コメント