正規表現の世界に足を踏み入れてみた
これまでコピペでなんとかしてきた正規表現ですが、とっつきにくき壁を取っ払って挑戦してみました。
そもそも正規表現とは、文字列をパターンで検索するときに使用する書き方のこと。
エスケープ処理が正規表現のことだと思っていたのは私です🤣
正規表現の基礎まとめ
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歩足を踏み入れることができました🙌
ググるといろんな特殊記号がでてきてヴッとなるんですが、簡単なパターンだと初心者でも全然いけました。(たぶん)
これから積極的に正規表現にぶつかっていこうと思います!
正規表現問題サイトも活用してくぞ~~
それでは、 ☁️ぼんっ