はじめに
こんにちは!ソーイ株式会社の木寺です。
プログラムを書いているときに、「このメソッド、どこだっけ」と検索すると似た名前がずらっと並んで、結局どれか分からないといったことはありませんか?
私自身似たような経験は業務中何度もありました。もちろん今もあります。
このような問題は、『正規表現』というものを上手に活用すると、解決するらしいのです!!
今回は、自分を含めこれを読んでいただいた方の検索が上手くなる入口として、正規表現についてまとめていきます!!
マッチ例は、VS Code のファイル内検索で確認しています。すぐ試すなら https://regex101.com が使えます。(使用される場合は以下の画像のように左側のFLAVORでJavaScriptの選択をお願いします。)
想定読者
この記事は、次のような人を想定しています。
- 正規表現を聞いたことはあるが、内容を知らない人
- 効率よく仕事をしたい人
- 正規表現のチートシートを見たい人
正規表現とは
正規表現(Regular Expression)は、探したい文字列の条件を、決まった記号で書くための書き方です。
正規表現では、言葉そのものに加えて、「それで始まってほしい」「この単語を含んだうえで、最後はこれにしたい」「この位置には数字が入っていてもいい」といった条件を一緒に書けます。条件に合う文字列を、まとめて探すための書き方です。
プログラムの中を探すときも同じです。「get」とだけ書くとgetUserもgetItemも、名前の途中にgetが含まれるものまで並びます。「getで始まり、Userで終わる名前」と書ければ、候補をぐっと減らせます。はじめに書いた「似た名前が多すぎる」を、条件を足して絞り込むための道具が正規表現です。
たとえば次のパターンは、単語としてgetで始まりUserで終わる名前に当たります。
\bget\w*User\b
getUserやgetCurrentUserにマッチします。getItemは終わりがUserではないので外れ、forgetUserはgetが単語の先頭ではないので外れます。getUserByIdも、Userの後ろに文字が続くのでマッチしません。\bは単語の境界、\w*は英数字とアンダースコアの0回以上です。\wは後の節で扱います。
この条件を書くために使う特別な記号を、メタ文字と呼びます。「何でもいい1文字」「繰り返し」「これか、あれか」のように、文字そのもの以上の意味を持たせた記号です。普通の文字とメタ文字を混ぜて、探したい形を一文で表します。
たとえば、
- 『sewii』という文字を含んでほしい
- ただし、それで始まってほしい
- 後ろに数字が付いていても、同じ人として見つけてほしい
正規表現は、このお願いを記号の並びに翻訳したものです。どの記号がどのお願いなのかは、次の節から一つずつ見ていきます。
メタ文字の解説
ここからは、頻出のものに焦点をおいて解説を行っていきます!
.任意の1文字
.は、改行以外の任意の1文字にマッチします。
c.t
catやcut、c0tにはマッチします。ctやcartにはマッチしません。
^ $先頭と末尾
^は文字列の先頭、$は文字列の末尾です。VS Code の検索では、行ごとの先頭と末尾にマッチします。
^cat$
このパターンは、文字列全体がcatであるときだけにマッチします。catとだけ書くと部分一致なので、catsやcategoryにもマッチします。^と$を付けると、この2つは外れます。
* + ? {}繰り返し
直前の1文字やグループを、何回繰り返すかを指定します。cats*の*は、単語全体ではなく直前のsだけに付きます。
| 書き方 | 意味 | 例 | マッチする例 |
|---|---|---|---|
* |
0回以上 | cats* |
cat/cats/catss
|
+ |
1回以上 | cats+ |
cats/catss
|
? |
0回か1回 | cats? |
cat/cats
|
{n} |
ちょうど n 回 | ca{2}t |
caat |
{n,m} |
n回以上 m回以下 | ca{1,3}t |
cat/caat/caaat
|
{n,} |
n回以上 | ca{2,}t |
caat/caaat
|
*は0回を含むので、cats*はsが無くてもマッチし、catも対象になります。sが1回以上ほしいときはcats+です。a*のように繰り返し対象しか書かないパターンは、空文字列にもマッチします。
^cats?$はcatとcatsにマッチします。?が直前のsだけに掛かるためです。catssはsが2回なので、文字列全体としてはマッチしません。^と$を付けないcats?は部分一致になり、catssの先頭のcatsにマッチします。
.+や.*は、できるだけ長くマッチします。".+"で"a", "b"を探すと行全体にマッチします。最短にしたいときは、繰り返しの直後に?を付けて.+?と書きます。".+?"なら"a"と"b"それぞれにマッチします。
[]文字クラス
角括弧のなかに書いた文字のどれか1文字、という意味です。
c[au]t
catとcutにマッチします。cotやc0tにはマッチしません。前のc.tはcotにもマッチしましたが、[]は中に書いた文字だけが対象です。
[a-z]は小文字のアルファベット、[0-9]は半角数字です。範囲は[a-zA-Z0-9]のように繋げて書けます。
先頭に^を書くと否定になります。c[^o]tはcotにはマッチしません。[^0-9]なら、半角数字以外の1文字です。この^は「先頭」ではなく、「この文字クラスを否定する」という意味です。
文字クラスの中では、.や|もただの文字として扱われます。[cat|dog]は「catまたはdog」ではなく、c/a/t/|/d/o/gのどれか1文字です。「または」を書きたいときは、次の|を使います。
|または
左右のどちらかにマッチします。
cat|dog
catにもdogにもマッチします。|は優先度が低く、^cat|dog$は「先頭がcat」または「末尾がdog」という意味になります。そのためcategoryやhotdogにもマッチします。文字列全体をcatかdogだけにしたいときは、次のグループを使って^(cat|dog)$と書きます。
()グループ
括弧は、複数の文字をひとかたまりにします。量指定子や|の効く範囲を決めたいときに使います。
^cat+$
^(cat)+$
^cat+$はcaのあとにtが1回以上です。catやcattにマッチし、catcatにはマッチしません。^と$がないcat+は部分一致なので、catcatの先頭のcatにマッチします。^(cat)+$はcatの繰り返しなので、catやcatcatにマッチします。
括弧で囲んだ部分は、あとから取り出せます。左から数えて1番目の括弧が\1、2番目が\2です。(cat|dog) and \1は、cat and catやdog and dogにマッチします。cat and dogのように、前後が違う単語にはマッチしません。
グループにはしたいが、取り出しはしない、というときは(?:cat|dog)のように?:を付けます。パターンが長くなると、必要な括弧だけを番号付きで残せるので読みやすくなります。
\エスケープ
メタ文字を、記号としての意味ではなく文字そのものとして書きたいときに、直前に\を付けます。
cat\.com
これはcat.comという文字列にマッチします。catXcomやcatacomにはマッチしません。
よくエスケープするのは . * + ? ( ) [ ] { } | ^ $ \です。バックスラッシュそのものを表すときは\\と書きます。
\d \w \s省略記法
文字クラスを短く書くための記法です。大文字にすると意味が反転します。
| 書き方 | だいたいの意味 | 反転 | 例 |
|---|---|---|---|
\d |
数字 | \D |
cat\dはcat1
|
\w |
英数字とアンダースコア | \W |
cat\wはcatsやcat1
|
\s |
空白文字 | \S |
cat\sdogはcat dog
|
cat\dはcatの直後が数字1文字のときにマッチします。catだけにはマッチしません。cat\sdogは間に空白があるcat dogにマッチし、くっついたcatdogにはマッチしません。
\dは JavaScript では半角数字[0-9]と同じです。Python の標準では、全角数字のような Unicode の数字にもマッチします。半角だけに限定したいときは[0-9]と書くか、Python ならre.ASCIIを検討します。\wや\sも、言語によって対象の範囲が変わります。迷ったら、許したい文字を[0-9]や[A-Za-z0-9_]のように明示するほうが読み違えが少なくなります。
ここまでの対応表
| 記号 | 役割 | 読み方の例 |
|---|---|---|
. |
改行以外の任意の1文字 |
c.tはcatやcut
|
* |
直前を0回以上 |
cats*はcatやcats
|
+ |
直前を1回以上 |
cats+はcatsやcatss
|
? |
直前を0回か1回 |
cats?はcatとcats
|
{n,m} |
直前を n〜m 回 |
ca{1,2}tはcatとcaat
|
^ $
|
先頭と末尾 |
^cat$はcatだけ |
[] |
指定したうちの1文字 |
c[au]tはcatとcut
|
[^] |
指定以外の1文字 |
c[^o]tはcatやcut(cotは除く) |
| |
または |
cat|dogはcatかdog
|
() |
まとまり。取り出しもできる |
(cat)+はcatやcatcat
|
\ |
直後の記号を文字として扱う |
cat\.comはcat.com
|
\d \w \s
|
数字、英数字など、空白 |
cat\dはcat1など |
メタ文字を組み合わせた例
以下が業務内で使いそうな正規表現の例です。
ログ1行から日時とレベルを取る
^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(ERROR|WARN|INFO)\] (.+)$
次の行にマッチします。
2026-10-07 01:12:00 [ERROR] connection timeout
郵便番号
^\d{3}-?\d{4}$
100-0001にも1000001にもマッチします。-?が「ハイフンはあってもなくてもよい」だからです。100-00001は4桁を超えるのでマッチしません。ハイフンを必須にしたいときは?を外して^\d{3}-\d{4}$にします。
画像ファイル名
^.+\.(jpe?g|png)$
photo.jpg、photo.jpeg、photo.pngにマッチします。photo.png.bakやphoto.PNGにはマッチしません。
-
.+は、拡張子より前に1文字以上何かがある -
\.は、拡張子の手前にあるピリオドそのもの -
jpe?gはjpgとjpeg -
|でpngも許す -
$で末尾が拡張子であることを確認する
PNGも許すなら、パターン側を[Pp][Nn][Gg]のように書くか、大文字小文字を無視するフラグを使います。JavaScript ではi、Python ではre.IGNORECASEです。
先頭の.+を.*に変えると、拡張子だけの.jpgにもマッチします。+と*の差は、この「0文字を許すか」に出ます。
先頭が sewii で、後ろは数字
はじめに挙げた「sewii で始まり、後ろに数字が付いていても同じ人として見つけたい」は、次のように書けます。
^sewii\d*
sewii、sewii1、sewii01にマッチします。^で先頭をsewiiに固定し、\d*で数字は0回以上です。mysewiiのように前に文字がある名前にはマッチしません。sewii1abcは、先頭のsewii1には部分一致します。名前全体を sewii と数字だけにしたいときは^sewii\d*$にします。
まとめ
- 正規表現は、文字列のパターンを記号で書く記法
- 普通の文字はその文字にマッチし、メタ文字は「任意」「繰り返し」「または」「位置」を表す
- メソッドが見つからないときは、「get」だけではなく
\bget\w*User\bのように始まりと終わりを指定して、候補を絞り込める
お知らせ
技術ブログを週1〜2本更新中、ソーイをフォローして最新記事をチェック!
https://qiita.com/organizations/sewii
