正規表現の世界に足を踏み入れてみた
これまでコピペでなんとかしてきた正規表現ですが、とっつきにくき壁を取っ払って挑戦してみました。
そもそも正規表現とは、文字列をパターンで検索するときに使用する書き方のこと。
エスケープ処理が正規表現のことだと思っていたのは私です🤣
正規表現の基礎まとめ
JSにおいては「正規表現オブジェクト」を通して利用し、2つの書き方がある。
- 正規表現リテラル
パターンが変化しない場合に使用すると良パフォーマンス!
対象範囲を表すデリミタは、JavaScriptの場合は/以外使えない。
const regex = /test/;
- コンストラクタ関数
RegExp()
実行時に正規表現をコンパイルするので、パターンが変化する・不明な時やユーザー入力などから取得するときはこっちを使う。
const regex = new RegExp('test');
メソッド
正規表現オブジェクトにはメソッドが格納されており、検索・抽出・置換などが簡単に処理できる。
正規表現 - JavaScript | MDN
オプション(フラグ)
検索モードの変更をする時は、以下のように正規表現の後ろにフラグを記述する。
フラグ種類はどんな順序で記述しても問題ない。
const regex = /test/gm;
const regex = new RegExp('test', 'gm');
エスケープ処理
特殊文字を文字として使用するときは、エスケープ処理が必要になる。
特殊文字の前にバックスラッシュ(\)を記述する。
資料によって\だったり¥だったりするが、どっちでもOK
マッチ部分の記憶
マッチした部分を後から再利用したいときには、パターンを( )で囲むことで記憶しておける。(=後方参照)(ちょっとこれは難しい…再勉強する…)
いざ実践!
現在JavaScriptの勉強として、入力されたGoogleDriveの共有リンク情報を書き換えるアプリをつくっているので、その中で正規表現の実践をしてみた記録です。
特定の文字列があるかどうかの判定パターン
https://drive.google.comが文頭にあるhttps://drive.google.comの直後に/file/があり、かつ任意の文字列が続く
上記2つの判定パターンは「https://drive.google.com/file/が文頭にあり、かつ任意の文字列が続く」という風に一つにまとめるべきです。
しかし今回の実装ではそれぞれの条件に合わせたバリデーションメッセージを表示させることが目的なので、「/file/ディレクトリがある」というパターンを別に分けています。
なにはともあれ、ググりつつ書いてみる。
肯定先読みというテクニックがあると知って、試しに使ってみました。
/^(?=.*drive\.google\.com).*$/;
^で文頭一致を設定- 肯定先読み
(?=…)で指定文字列があるか探す - 指定文字列には「任意の文字列(
.)が0個以上(*)ある後にdrive.google.comという文字列がある」というものを指定 - もし指定文字列がマッチすれば、改めて文頭から文末(
$)までに任意の文字列(.)が0個以上(*)ある」パターンとマッチするかを検索
つまり「drive.googleがどっかに含まれる文字列」というパターンになります。
改めて見てみるとhttps://の指定は入れた方が確実な気がするし、そうしたら肯定先読み使う必要ないな?と思い、書き直し🤔
/^https:\/\/drive\.google\.com.*$/;
思いっきりシンプルになりました。
^と$で文字列全体を設定https://drive.googleがあって、その後ろに任意の文字列が0個以上(.*)あるか
これでひとまず一つ目のマッチ条件「https://drive.googleが文頭にある」を満たせました。
次は「https://drive.google.comの直後に/file/があり、かつ任意の文字列が続く」というマッチ条件を考えます。
ひとまず/file/の検索だけでパターンを考えてみます。
/(?=.*\/file\/).*$/;
これも肯定先読みを使ってパターンを作成してみました。
前項と違う点は文頭指定^がないことだけで、文字列全体のどこかに/file/という指定文字列があるか検索します。
ただこれだと「https://drive.google.comの直後」という条件には当てはまりません🙄
ということで、また肯定先読みはやめて再考。
/^https:\/\/drive\.google\.com\/file\/.+$/;
^と$で文字列全体を設定https://drive.google.com/file/があって、その後ろに任意の文字列が1個以上(.+)あるか
https://drive.google.com/file/以降にもURL情報は続くので、*ではなく+を記述して1個以上の文字の繰り返しという条件を追加しました。
これで「https://drive.google.comが文頭にある」、「https://drive.google.comの直後に/file/があり、かつ任意の文字列が続く」という条件を満たすパターンをそれぞれ作成することができました。
これでバリデーションメッセージの表示条件分岐もばっちりですいえい
特定の文字列間の中身を抽出
続いて文字列を変換させるため、変換箇所のパターンを作成します。
https://drive.google.com/file/d/画像ID/view?usp=sharingの画像IDを抽出
つまり/d/と/viewの間の文字列を抽出したい、ということなので、肯定先読みと肯定後読みを使って表現してみました。
/(?<=\/d\/).*?(?=\/view)/;
(?<=\/d\/)で/d/が見つかれば、そのあとに任意の文字列が0個以上あるが見る- それがマッチすると
/d/の後ろにマッチの基準を置く - そのマッチの基準から
/viewが見つかれば、/viewの前にマッチ基準を置く /d/と/viewの間の文字列がマッチ!
このとき任意の文字列が0個以上を.*ではなく.*?で表現しているのは、マッチした1個目だけを抽出するためです。(最短一致)
今回の実装内容ではつけなくても問題なさそうだけど念のために👻
もし.*を使用している時に複数の/d/と/view があった場合(例えばhttps://drive.google.com/file/d/画像ID/view?usp=sharing/d/画像ID/viewみたいな…)、画像ID/view?usp=sharing/d/画像IDとマッチしてしまう。
ということで、簡単なパターンのみの作成にはなっちゃいましたが今回はここまで!
おわり
正規表現がなにものかも理解してない民が、正規表現の世界へ1歩足を踏み入れることができました🙌
ググるといろんな特殊記号がでてきてヴッとなるんですが、簡単なパターンだと初心者でも全然いけました。(たぶん)
これから積極的に正規表現にぶつかっていこうと思います!
正規表現問題サイトも活用してくぞ~~
それでは、 ☁️ぼんっ