プログラムをコーディングしていると、意図しない結果になって原因がわからず、ひたすら時間だけが過ぎていく状態がたまにあります。
多くの場合、言語仕様を取り違えていたり、複雑な組み合わせで間違いに気が付きにくい場合などですが、簡単な処理であってもこういう事態に陥ることがあり、所謂「ハマる」という状態です。
今回はjavascriptにおける正規表現からの戻り値で、想定の結果にならずに困ったという話になります。
やりたかったこととその結果
正規表現を使い場面は結構多く、特定の文字列から、指定の形式にマッチしているかどうか、とある単語が含まれているかを検索する場合や、入れ替えする時などに非常に便利に使えます。
例えば、以下のような文字列から、 "{*}"の*部分を一覧で抜き出したい時・・・
var str = "{a}-{b}-{c}-{d}";
var str = "{a}-{b}-{c}-{d}";
var reg = RegExp(/\{(.+?)\}/,"g");
var res = reg.exec(str);
console.log(res2);
> ["{a}", "a"]
execの場合は、gオプションが効かず、最初にマッチしたものをそのパターン毎に配列で返してくれます。
var str = "{a}-{b}-{c}-{d}";
var reg = RegExp(/\{(.+?)\}/,"g");
var res = str.match(reg);
console.log(res1);
> ["{a}", "{b}", "{c}", "{d}"]
次にmatchで行うとgオプションは効きますが、"(.+?)"箇所の抜き出しが返されません。
PHPでやると、多次元配列でマッチしたパターン分と、ヒットした個数がそのまま取得できるんですが、javascriptはどうやらそれとは結果が違って、1次元配列でしか返らない仕様のようです・・・
リファレンスページには、こうした例の表記はされていないようなので、javascriptの仕様として理解しておかないと行けないようですね。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/match
PHPと同じ様な結果を返すための強引な方法
mapプロパティで強引に検索結果を文字列コントロールするやり方が最もシンプルかもしれません。
var str = "{a}-{b}-{c}-{d}";
var reg = RegExp(/\{(.+?)\}/,"g");
var res = str.match(reg).map(function(value){return value.replace("{","").replace("}","");});
console.log(res);
> ["a", "b", "c", "d"]
また、PHPのような多次元配列で返すには以下のように書くパターンもあります。
var str = "{a}-{b}-{c}-{d}";
var reg = RegExp(/\{(.+?)\}/,"g");
var res = str.match(reg).map(function(value){return [value , value.replace("{","").replace("}","")];});
console.log(res);
> [["{a}","a"],["{b}","b"],["{c}","c"],["{d}","d"]]
ちょっと強引な気もしますね。
でもよく考えたら、以下のようにした方が、自然な結果を得られるかもしれませんね。
var str = "{a}-{b}-{c}-{d}";
var reg = RegExp(/\{(.+?)\}/,"g");
var res = str.match(reg).map(function(value){return /\{(.+?)\}/.exec(value)});
console.log(res);
> [["{a}","a"],["{b}","b"],["{c}","c"],["{d}","d"]]
結果的に、matchとexecを同時に使うという贅沢なプログラムが出来上がりました。
いや〜言語仕様ってよく出来てますね・・・
そもそも、このコードが標準搭載されていればいいのに・・・
0 件のコメント:
コメントを投稿