Istio のサンプルの bookinfo にre =/^(.*?;)?(user=jason)(;.*)?$/
という正規表現が出てくる。
これは、Cookie にマッチさせるための表現らしい。
ところが、これをTypeScript で次のようなプログラムを作ってみるとマッチしない。正規表現がテストできる、このサイトRegular Expression Test Driveの方でもマッチしない。しかし、サンプルは正常に動作している。とても気になったので上記の正規表現をちゃんと理解してみようと思った。
^ 先頭からのマッチ
まず汎用の下記のような関数を書いてみる。
function exec(re: RegExp, matches: Array<string>) {
for (let chr of matches) {
console.log(`***: ${chr} :***`);
console.log(re.exec(chr));
}
}
^ は先頭からのマッチなので、下記のようにすると、予想どおり、最後の1つを除いてマッチする。
// ^
console.log("^ ----");
let matches = ["hello", "hey", "head", "hinder"];
re = /^/
exec(re, matches);
. 任意の1文字
. は任意の一文字。改行はふくまれないので、これも最後以外はマッチ。
// .
console.log(". ----");
matches = ["a", "1", "*", "\n"];
re = /./
() グループ と? 直前の 0 もしくは 1 回の出現
*
は直前の0もしくは複数の繰り返しなので .*
で任意の文字列。つまり()の中は任意の文字列; のパターンになる。下記の結果は、(.*;) user=jason
だと、最後の user=jason
を除いてマッチする。`(.*;)?user=jason
最初の、(.*;)user=jason
にはいづれもマッチしない。必ずxxx; のパターンを要求するので。?をつけると、0 か、1の出現なので、なくてもよくなるので、マッチする。ちなみに、/(.*;) user=jason/
にすると、最初の2つだけマッチする。3つ目は、スペースが入っているのでマッチしない。
console.log("(.*;) -----");
re = /(.*;)user=jason/;
matches = ["name=ushio; user=jason",
"name-ushio; some=yamagata; user=jason",
"user=jason"]
exec(re, matches);
// (.*;)?
console.log("(.*;)? ----");
re = /(.*;)?user=jason/;
exec(re, matches);
そして、本来の理解
Cookie は、 name=xxxx; user=jason; ... " という形態で記述される。
であるので、/^(.*?;)?(user=jason)(;.*)?$/
に関しては、マッチちない。name=xxx; user=jason
はマッチしない。user=jason
はマッチするけど。理由は、先頭マッチの場合は、user=jason のスペースがマッチしないから。
let ma = ["NAME=v2tester; user=jason", "user=jason"];
re =/^(.*?;)?(user=jason)(;.*)?$/
console.log ("------------------ answer");
console.log(exec(re, ma));
こう変えるとちゃんとマッチする。なぜ上記のでIstio はオッケーなのかが謎なので質問してみる。
ma = ["NAME=v2tester; user=jason", "user=jason"];
re =/^(.*?;\s?)?(user=jason)(;.*)?$/
console.log ("------------------ answer2");
console.log(exec(re, ma));