【初心者向け】駆け出しでもわかる!正規表現の超入門
プログラミングを習っていると必ずと行っていいほど、 初学者の壁となって立ちふさがるのが「正規表現」ですね。
私も最初習ったときはなんだこれ!?ってなりました。
実は覚えるコツとしては「何度も使う」以外存在無いんですよね……
組み合わせ方は無限大なので1つ1つの記号の意味を覚えていく必要があります。
私も何度も何度も使ってきて、普段使うものは覚えたのですが 完全に理解しているわけではないです。
ただ、使っていると1つ1つ意味がわかってきて 後はパズルのように組みわせて使っています。
今回は私がよく使っている便利な正規表現の書き方をお教えします。
一気に覚えるとしんどいので、1つ1つ覚えていきましょう。
何かが1つ以上含まれている場合に1行一致させる
私はこの正規表現を結構使うことが多いですし、 一番最初に覚えた正規表現がこのやり方です。
通常検索だと文字もしくは単語単位でしかとれませんが、 この正規表現を使うと一致すれば1行全て取ることができます。
正規表現の書き方はエディタによって若干異なったりしますが、 今回紹介するのは恐らくどのエディタでも言語でも使える方法です。
例題として以下のURLのリストがあったとします。
- ttps://A123BCDE.com
- ttps://BC456DEF.net
- ttps://CDF789GH.info
- ttps://DFGH095I.org
- ttps://ACEGI753.xyz
- ttps://1BD2FHJ3.shop
上のURLもしかするとアクセスできるかもしれないのですが、 アクセスしないようにしてください。
リンク自体は外してますが、念の為誤アクセスしないように先頭のhは抜きました。
このリストを使って正規表現を使ってみましょう。
+を使って指定の文字が1つ以上含まれる行を探そう
ではこのURLの中から「A」が含まれる行を検索してみましょう。
正規表現のサーチの所に入力文字にの後に「+」を付けると
+の左にある文字が1つ以上含まれている場合という正規表現になります。
今回で言えばこう書きます。
「A+」
これで「Aが1つ以上含まれている場合」という正規表現が完成しました。
簡単ですね!
でもこれだと検索するのが「A」だけになってしまうので、 今回やりたいのは「Aが含まれている行」をとりたいわけなので 頭からお尻まで検索する正規表現を組み合わせます。
+より*のほうが個人的には便利だと思ってる
「+は1つ以上含まれている」という意味ですが、 「*は0つ以上含まれている」という意味になります。
何が違うのかと言うと、「A*」にするとAが0つ以上含まれる場合となってしまい 先頭においている「A」が意味をなしていない状態になります。
それなら+のほうがよくない?ってなりますが、 確かにAというワードが確実に入っているというものを探したいときには+は便利です。
ですが、*は何かが含まれていればというあいまいで不覚的な時に効果を発揮します。
*は次に紹介するコマンドと組み合わせるととても便利になります。
.(ドット記号)はすべての「文字」を検索する
文字と文字列の違いはわかりますよね?
文字とは「1つの字」を指します。
ドット記号を使うことでどの文字も検索することができます。
でもこれ単体だけだと殆ど意味をなしません。
先ほど紹介した*、もしくは+を使うことによって絶大な効果を発揮します。
使い方は次の^と$を覚えてからにしましょう。
^を使うと先頭・$を使うと末端
一応全角で書いてますが、半角で入力してください。
入力する正規表現のコマンドを最初に書いておくと
「^.*?A.+$」
おい習ってないのがでてきたぞ!って思うかもしれませんが1つずつ見ていきましょう。
まずは^と$からです。
^は、数学だと累乗の計算に使われる記号ですね。 読み方は「ハット」または「ハットキャレット」だそうです。 以後ハットと読んでいきます。
これは先頭を意味する記号となっています。
なので^を付けると頭から検索という意味になるわけですね。
$はその名の通りドルマーク記号ですね。以下ドルでいきます。
$は末端を意味します。
それでは先程の「^.*?A.+$」は何を意味するのか1つずつ 復習する感じで見ていきましょう。
^を使うと先頭1文字を一致させる
^は先頭を意味するコマンドでしたね
これだけを使うと「すべての行の先頭の1文字(先頭ならどんな文字でも検索)」だけをサーチすることが出来ます。
あくまで「先頭」だけを意味するのでこれ単体ではほぼ意味無しです。
.を使うと何かの文字を一致させる
次にドットを組み合わせてみましょう。
「^.」
となります.
ドットは何の文字でもサーチするって意味でしたね。
そしてこれも正直あまり意味は有りません。
先頭の何か1文字という意味になるためです。
これなら^単体でいいかなと思います。
次に行きましょう。
*は1つ前の文字0個以上ある場合に一致させる
お次は「^.*」の意味になります。
これで「先頭から(^)何か文字が(.)0個以上含まれている(*)場合」という意味になります。
でもこれだとすべての行が検索されてしまうので正規表現の意味が完全になくなってしまいますね(笑)
しかし先頭の^をttpsに置き換えてやると、「ttpsから始まる1行を取得」という事ができるようになります。
これだけでも事務仕事なんかをするとき結構便利です。
ちなみに私はURLが含まれる行を取り出す時にこれをよく活用していました。
?は後に置く文字によって検索する位置を変化させる
ちょっと曲者なのがこの「?」ですね。
まだ紹介していなかったのですが組み合わせないと意味がない記号なのでココで説明します。
?は正確にはちょっと違うのですが
「どこまで検索するか」という時によく使っています。
今回の正規表現コマンド「^.*?A.+$」で見てみると?のあとにAがきていますよね。
ここまでのコマンドをみてみると「^.*?A」だと以下のようになります。
「先頭から(^)何か文字が(.)0個以上含まれている(*)場合で、Aが含まれる所まで(?A)」一致
という意味になります。
これでAが行の何処にもない場合は一致しなくなります。
とても便利!
正規表現コマンド「?」の本来の意味
ちょっと混乱するかもなので、ここの項目は飛ばしでも問題ないです。
?の本来の意味を知りたい人だけみてください。
私が?を使うのは先程紹介した内容で使うことが多いのですが、クエスチョンマークの本来の意味とは
「直前の文字が 0個か1個 の場合にマッチ。最長一致。条件に合う最長の部分に一致」
となっています。
文字の後ろではなく前に作用する正規表現です。
例えば「Google」というワードがあって正規表現で「Googl?」というコマンドを入れると
- Google(最後のeはなんでもいい)
- Googl
の2パターンを検知することになります。
最後がなにもないか、eであろうがなんであろうが1文字あれば検知するということですね。
正直、あぁん?ってなるぐらい意味わからないですよね。
私は「.*?A」という組み合わせのコマンドをよく使っています。 (最後のAは検知したい任意のワード)
これを紐解いてみると
「任意の1文字が0個以上続く場合で直前の文字が0個か1個ある場合」
はい、この時点で意味わからなくなってきますね(笑)
「.*?」だけだと1文字1文字すべてを検知します。
この「1文字1文字」というのがミソで、検知は1文字ずつするので検知数は入力文字数とイコールになります。
なのでこれだけだとあまり意味がないので、ハテナの後ろに文字を入れると、 その「入れた任意の文字を含んだところかつ、その文字が最初にでてくるところまで」検索してくれます。
なので最初に後ろに作用するコマンドと紹介したわけですね。
?の本来の使い方としてはわかりやすい例をあげると
「jpgかjpeg」や「htmかhtml」と同じものなのに2つの拡張子を持つ物があった場合
jpg?やhtm?とすると両方サーチすることが出来ます。
プログラミングではこっちの使い方をすることが多いと思いますが、 テキストエディタで1行を検索するときは「.*?A」的な使い方をよくしています。
組み合わせ方次第で様々なことができるので本当に魔法みたいですね。
+は1つ前の文字が1つ以上含まれる場合
Aの次の.はもう説明しなくてもわかりますよね。
一応言うとAの後に何か文字が入っている場合になります。
そして次の+となっているので「何か文字が1つ以上含まれている場合」というわけになります。
$は末端を意味する
そして最後の$は末端という意味でしたね。
これ単体だけだと正直あんまり意味をなさないのですが、 組み合わせると便利な記号です。
ここまでのコマンドの意味を再度確認してみましょう。
- 先頭から(^)何か文字が(.)0個以上含まれている(*)場合で
- なおかつAが含まれる所まで(?A)検索したのち
- Aの後に何か1文字以上(.+)あり末端まで検索する($)
という意味になります。
状況に応じて「A」の部分を変化させたり+を*に変えたりすれば、 かなり汎用性の高いあいまい検索ができるようになります。
正規表現はだいたいのプログラミング言語共通で使える汎用魔法
正規表現を使うことによってあいまいな検索が可能になり、 プログラミングの幅がすごく広がるため様々なソフトに使用されています。
プログラマーやエンジニアとして働く上ではもちろん必須勉強項目ですし、 実はエクセル(VBA)とかでも使えたりするので事務仕事にもかなり効果を発揮します。
1ずつ記号の意味を知れば組み合わせ次第で文字を検索できる自由度がかなり高まります。
複雑になった場合は1回ある程度条件で絞って新しいリストを作ってから 再度正規表現で絞り込むというやり方が可読性もあっておすすめです。
私もまだ10%ほどしか正規表現を理解していませんが、 今回教えたものはかなり幅広く使えますし実践でも有効です。
番外編:Aが先頭の場合
そういえばここまで書いてみて作ったリスト殆ど活用してないですね(笑)
まぁ次の正規表現の勉強に流用させてもらいましょう。今回はここまでです。
そして今回やってて疑問に思った人もいるかと思う
「先頭がAだった場合」「末端がAだった場合」
について見てみましょう。
先頭がAだった場合
^は先頭を意味する記号ですが「^.」だと先頭が何か1文字の場合となりますが 「^A」とするとAから始まってる行という意味になります。
ただこれだけだと「Aから始まってる行の先頭のAだけ」しかサーチできていないので ドットや*などの記号を組み合わせる必要があったわけです。
末端がAだった場合
「A.+$」はAから始まってその次に何か文字が1つ以上含まれているところから末端まで
という意味になりますね。
でもこれだとAが末端でその後が改行になっていたらサーチできないことになります。
+は1つ前のドットのせいでAの後に何か1文字以上含まれている場合じゃないとダメになっています。
ですが「A$」だとAで終わってる行しかとれなくなってしまい、 もしAの後に何かが含まれてしまった場合Aが含まれていたとしても検索できなくなってしまいます。
なので+より便利な「0回以上という*」の方が便利だということですね。
「A.*$」だとAの後に何かあってもなくても末端までサーチという意味になります。
この「ドットアスタリスクドル」というものはめちゃくちゃ使えるのでしっかりと記憶しておきましょう。