JavaScriptでよく使う文字列マッチングを、その仕組みも含めて解説。
たとえば、以下のような状況で使用できる。
- ページURLのパス(
window.location.pathname
)が特定の文字列で終わるときに●●したい。 - リファラ(
document.referrer
)に特定の文字列を含むときに●●したい。 - UserAgent(
window.navigator.userAgent
)に特定の文字列を含むとき●●したい。
この記事で扱うマッチング
##完全一致
以下のような処理で完全一致を実現できる。
var string = 'hoge';
var pattern = 'hoge';
if(string === pattern){
// 完全一致のときの処理
}
解説
厳密等価演算子===
を使用してデータ型も含めて完全一致の比較を行う。
等価演算子==
で完全一致処理を行おうとすると、暗黙の型変換が行われて意図せぬ結果になることがあるので、特別な理由がない限りは厳密等価演算子を使用することをオススメ。
→ JavaScript 忘れがちな === と == の違い
##前方一致
以下のような処理で前方一致を実現できる。
var string = 'isogram';
var pattern = 'is';
if(string.indexOf(pattern) === 0){
// 前方一致のときの処理
}
解説
indexOf()
はターゲット文字列内の何文字目でパターン文字列が見つかったのか返す。
0文字目,1文字目,..と数え上げるので、最初の文字で見つかった場合は0
が返ってくる。これを利用して前方一致の判定を実現できる。
###前方一致のコードを短縮する
var string = 'isogram';
var pattern = 'is';
if(!string.indexOf(pattern)){
// 前方一致のときの処理
}
JavaScriptにおいて数値を論理値に変換したときに0
はfalse
、それ以外の数はすべてtrue
として扱われる。
つまり、indexOf()
は前方一致したときのみfalse
と見なされる値を返す、そうでないときはtrue
と見なされる値を返す性質を持っている。
これを利用して、indexOf()
の結果を否定演算子!
により反転すれば短いコードで前方一致の判定ができる。
活用例
→ 目的のクエリパラメタの値を取得するコード - Qiita
###ES6バージョンの前方一致
ES6が使える環境なら、startsWith()
でOK。
var string = 'isogram';
var pattern = 'is';
if(string.startsWith(pattern)){
// 前方一致のときの処理
}
##部分一致
以下のような処理で部分一致を実現できる。
var string = 'isogram';
var pattern = 'og';
if(string.indexOf(pattern) > -1){
// 部分一致のときの処理
}
解説
indexOf()
では**マッチしなかったとき-1
**を返す。マッチしたときは0
以上の整数を返す。これを利用して部分一致の判定を実現できる。
###部分一致のコードを短縮する
var string = 'isogram';
var pattern = 'og';
if(~string.indexOf(pattern)){
// 部分一致のときの処理
}
~
は数値をビット反転する演算子であり、「indexOf()
でマッチしなかったとき返ってくる数値」である**-1
をビット反転した数値は0
になる。
0
はif文においてfalse
と判定され、それ以外の数はすべてtrue
として扱われるため、
これを利用して、indexOf()
の結果を~
でビット反転すれば短いコードで部分一致の判定ができる。
参考)
(10進数の)数値xをビット反転した値 = -(x + 1)
※分かりやすくするために2進数を符号付き4bit整数で表しているが、実際の処理では符号付き32bit整数として処理されている。
よって、
~string.indexOf(pattern)
により部分一致が成立する。
活用例
→ UA情報から電話デバイスかどうかを判定するコード - Qiita
→ Cookieをオブジェクト形式で取得するJavaScriptコード - Qiita
###ES6バージョンの部分一致
ES6が使える環境なら、includes()
でOK。
var string = 'isogram';
var pattern = 'og';
if(string.includes(pattern)){
// 部分一致のときの処理
}
##後方一致
以下のような処理で後方一致を実現できる。
var string = 'isogram';
var pattern = 'am';
if((string.lastIndexOf(pattern)+pattern.length===string.length)&&(pattern.length<=string.length)){
// 後方一致のときの処理
}
解説
lastIndexOf()
はindexOf()
と同じく、パターン文字列が見つかる場所をターゲット文字列の中から探す関数だが、こちらはターゲット文字列の後方から探す。
indexOf()とlastIndexOf()の動作の違い
'aaaa'.indexof('a'); // -> 0
'aaaa'.lastIndexof('a'); // -> 3
「後方から探したときにターゲット文字列が見つかった場所 + パターン文字列の長さ」は、後方一致した場合ターゲット文字数と一致する。
ただし、この計算は
「ターゲット文字列の長さ+1 = パターン文字列の長さ」であったときも成立するため、
pattern.length<=string.length
となっていることも確認した上で後方一致の判定を行う。
よって、
(string.lastIndexOf(pattern)+pattern.length===string.length)&&(pattern.length<=string.length)
により後方一致が成立する。
###ES6バージョンの後方一致
ES6が使える環境なら、endsWith()
でOK。
var string = 'isogram';
var pattern = 'am';
if(string.endsWith(pattern)){
// 後方一致のときの処理
}
正規表現による一致
以下のような処理で正規表現による一致を実現できる。
var string = 'isogram';
var pattern = /^i\w{2}gra\w?$/;
if(pattern.test(string)){
// 正規表現一致のときの処理
}
解説
- test()は正規表現のマッチを調べる関数。
- このとき、patternは文字列ではなく、正規表現オブジェクトであることに注意。
- 行頭記号
^
や行末記号$
を使用しないと部分一致として作用するので注意。 - マッチした文字列を取得したい場合はmatch()やexec()を使用。
正規表現をチェックするときに参考になる記事
→ 正規表現チェックツールまとめ
意図せずES6の便利さがよくわかる記事になってしまいました。
ES6を使えば呪文みたいなコードを書く必要がなくなるので、
使える環境ではES6を使っていきたいです。
参考になるリンク
ES6の概要と、最新ブラウザに対応させる「Babel」の使い方 | ES6のある星に生まれて
各種ES6環境構築まとめ(Typescriptもあるよ) - Qiita
完