文字クラスで候補を絞る
角かっこ [ ] で囲むと、その中のどれか1文字にマッチする「文字クラス」になります。[abc] は a か b か c のいずれか1文字を表し、[0-9] のようにハイフンで範囲も書けます。先頭に ^ を置いた [^0-9] は「数字以外の1文字」という否定の意味になります。[A-Za-z0-9] のように範囲を並べれば英数字をまとめて指定できます。よく使う組み合わせは短縮表記の \d(数字)や \w(英数字とアンダースコア)でも表せます。
前の項目で . が「任意の1文字」を表すと学んだ。だが現場で書いてみると、すぐに物足りなさにぶつかる。「任意ではなく、この中のどれか1文字だけを許したい」という場面が、数えきれないほどあるのだ。
「数字1文字」「a か b か c のいずれか」「英字だけ」。候補をあらかじめ絞り込みたい。
これを実現するのが文字クラスで、角かっこ [ ] を使って書く。
. が無条件に1文字を受け入れるのに対し、文字クラスは「許す文字の集合」を自分で定義できる、より精密な道具だと考えてほしい。検索の精度を上げ、余計なものを拾わないようにする要になる。
前の項目のメタ文字が「どんな1文字でもよい」という大づかみの指定だったのに対し、ここからは「どの1文字を許すか」を細かく決めていく。
🎯 角かっこに並べた文字は、何文字に当たるのか
[ ] の中に文字を並べると、そのいずれか1文字にマッチする。[abc] は「a か b か c のどれか1文字」を表し、cat の a や cup の c に当たる。
ここで取り違えやすい点がある。いくつ文字を並べても、一致するのは1文字だけだ。[abc] は3文字に一致するのではなく、3つの候補のうちのどれか1文字に一致する。
複数文字のくり返しが欲しければ、後で学ぶ量指定子と組み合わせて [abc]* のように書く。
文字クラスは「ここに来てよい1文字の顔ぶれ」を列挙したもの、とイメージすると分かりやすい。
たとえば gr[ae]y と書けば、つづりの揺れる gray と grey の両方を一つの式で拾える。候補を並べるだけで、表記ゆれを一網打尽にできるわけだ。
📏 連続する候補を、ひとつずつ書くのは面倒ではないか
0から9までを [0123456789] と書くのは骨が折れる。候補が連続しているときは、ハイフン - を使って範囲で書ける。
[0-9] は0から9までの数字1文字、[a-z] は小文字の英字1文字、[A-Z] は大文字1文字を表す。
範囲は並べて書くこともでき、[A-Za-z] なら大小の英字、[A-Za-z0-9] なら英数字いずれか1文字を指す。たとえば「英字で始まる行」を探したいなら ^[A-Za-z] と書ける。
範囲指定のおかげで、候補をひとつずつ書き並べる手間が省け、式も短く読みやすくなる。
なお範囲はあくまで文字コードの並び順に沿う。[0-9] のような自然な範囲を使うぶんには直感どおりに動く。
一方で [a-Z] のように大文字と小文字をまたぐ逆転した範囲はエラーや予期しない結果になりやすい。英字を両方含めたいときは [A-Za-z] と分けて書くのが安全だ。
⚖ 同じ ^ なのに、なぜ意味が変わるのか
文字クラスの先頭に ^ を置くと、意味が反転して「この中以外の1文字」という否定の文字クラスになる。[^0-9] は「数字でない1文字」、[^a-z] は「小文字の英字でない1文字」を表す。
ここで前の項目を思い出すと、妙なことに気づくはずだ。^ は行頭のアンカーではなかったか。そう、同じ記号が二つの顔を持つ。
文字クラスの外側、つまり ^abc のように行頭で使う ^ はアンカー(行頭の位置)だ。だが [^abc] のように角かっこの中の先頭で使う ^ は否定の合図になる。同じ記号でも、角かっこの中か外かで役割がまったく違う、と区別して覚えてほしい。
たとえば grep '^[^#]' file は「先頭が # でない行」、つまりコメントでない行を抜き出す書き方だ。^(行頭)と [^#](# 以外の1文字)が組み合わさっている。
一つの式の中に、アンカーの ^ と否定の ^ が同居している好例だ。
✂ もっと短く書く方法はないのか
よく使う文字クラスには、短く書ける別名が用意されている。\d は [0-9](数字)、\w は [A-Za-z0-9_](英数字とアンダースコア)、\s は空白類にほぼ相当する。
ただし、便利だからと飛びつく前に一つ知っておきたい。これらの短縮表記は、grep では -P(PCRE)モードなど一部の方言でしか使えない。どこでも確実に動かしたいときは [0-9] のように角かっこで書くほうが安全だ。
具体例を見てみよう。grep '[0-9]' file は「数字を1文字でも含む行」を拾う。grep '[A-Z]' file なら大文字を含む行、grep '[^0-9]' file なら数字以外の文字を含む行を選ぶ。
後の項目で出てくる [0-9] と量指定子を組み合わせて桁数を指定する書き方は、ここでの文字クラスが土台になる。
🧯 角かっこの中では、なぜメタ文字が牙を抜かれるのか
つまずきやすいのは、角かっこの中ではメタ文字の多くがただの文字になる、という点だ。さっきまで特別だった記号が、角かっこに入ったとたんおとなしくなる。
たとえば [.] は「任意の1文字」ではなく「文字としてのドット」を意味し、[a.c] は a か . か c のいずれかになる。同様に [*] は文字としてのアスタリスクだ。
クラスの外では特別だった記号が、クラスの中では素直な文字に戻る、という切り替えを押さえておこう。
逆に、これを利用して [.] や [/] のように「エスケープしたい記号を1文字だけ角かっこで囲む」書き方をすると、\ を使わずに記号そのものを表せて読みやすくなることもある。
また、ハイフンを範囲ではなく文字そのものとして含めたいときは、[-abc] や [abc-] のように先頭か末尾に置くのがこつだ。中ほどに書くと範囲の意味になってしまう。
🛠 実務では、どこで効いてくるのか
実務では、文字クラスは入力の形式チェックや特定パターンの抽出で活躍する。後の項目で扱う、[0-9] を量指定子と組み合わせてIPアドレスらしき並びを拾う使い方はその典型だ。
設定ファイルから「先頭が英字の実効行」だけを取り出す、ログから「英大文字を含む行(多くはレベル表記)」を選ぶ、ユーザー名として許される文字だけかを確かめる、といった場面で繰り返し使う。
たとえば16進数らしき文字だけを許したいなら [0-9A-Fa-f]、英数字とハイフン・アンダースコアだけを許したいなら [A-Za-z0-9_-] のように、許可する顔ぶれを自分で組み立てられる。
. が大雑把に1文字を受け入れるのに対し、文字クラスは「どんな文字を許すか」を自分の言葉で定義できる、正規表現の中核的な部品だ。
まずは [0-9] [a-z] [A-Z] と、否定の [^…] を手に馴染ませておくと、検索の狙いを正確に絞れるようになる。