JavaScriptの正規表現でハマった
JavaScriptで、「.」や「..」に一致する文字列を抽出しようとしたのですが、ハマったのでメモ。
var dot = '..';
var str = 'ab';
// 「..」にはマッチして欲しい => alertが出ないとエラー
if( dot.match(new RegExp('^(\.){1,2}$')) ) alert('success 1');
if( dot.match(new RegExp('^(\\.){1,2}$')) ) alert('success 2');
if( dot.match(new RegExp(/^(\.){1,2}$/)) ) alert('success 3');
if( dot.match(/^(\.){1,2}$/) ) alert('success 4');
// 「ab」にはマッチして欲しくない => alertが出たらエラー
if( str.match(new RegExp('^(\.){1,2}$')) ) alert('error 1'); //=> ここでalertが出てしまう
if( str.match(new RegExp('^(\\.){1,2}$')) ) alert('error 2');
if( str.match(new RegExp(/^(\.){1,2}$/)) ) alert('error 3');
if( str.match(/^(\.){1,2}$/) ) alert('error 4');
Firebugのコンソール上で調べたところ、生成されるRegExpオブジェクトは下記の通りになっていた。
new RegExp('^(\.){1,2}$') //=> /^(.){1,2}$/ (.がエスケープされていない)
new RegExp('/^(\\.){1,2}$/') //=> /\/^(.){1,2}$\// (.がエスケープされていない)
new RegExp('^(\\.){1,2}$') //=> /^(\.){1,2}$/ (これは正しい挙動)
new RegExp(/^(\.){1,2}$/) //=> /^(\.){1,2}$/ (これは正しい挙動)
new RegExpする際に正規表現を文字列形式で渡すと、シングルクオート/ダブルクオートに関係なく評価された文字列を正規表現として扱う仕組みだったわけだ。
つまり、ハマった原因は自分がRuby脳になってたせい。なんてこったい!
ちなみに、正規表現作成時におけるシングルクオート/ダブルクオートの解釈は、言語別に見ると下記のような感じでした。
言語別 正規表現作成時におけるシングルクオート/ダブルクオートの解釈
#[Ruby]
Regexp.new('^(\.){1,2}$') #=> /^(\.){1,2}$/
Regexp.new("^(\.){1,2}$") #=> /^(.){1,2}$/
#[Python] ※ちなみに、Pythonはre.compileすると SRE_Match object が返るので、実行結果に基づく予想
import re
re.compile('^(\.){1,2}$') #=> /^(\.){1,2}$/
re.compile("^(\.){1,2}$") #=> /^(\.){1,2}$/
#[PHP] ※PHPはRegExpオブジェクトが存在しないみたいなので、実行結果に基づく予想
ereg('^(\.){1,2}$', $hoge) #=> /^(\.){1,2}$/
ereg("^(\.){1,2}$", $hoge) #=> /^(\.){1,2}$/
#[JavaScript, ActionScript]
new RegExp('^(\.){1,2}$') //=> /^(.){1,2}$/
new RegExp("^(\.){1,2}$") //=> /^(.){1,2}$/
バックスラッシュに対するエスケープの有無を、分かりやすく図にすると下記のようになる。
| Ruby | Python | PHP | JavaScript | ActionScript | |
|---|---|---|---|---|---|
| シングルクオート | 不要 | 不要 | 不要 | 要 | 要 |
| ダブルクオート | 要 | 不要 | 不要 | 要 | 要 |
大きく分けて、
ダブルクオートのみバックスラッシュにエスケープが必要になる「Ruby系」
シングルクオート・ダブルクオートに関係なくエスケープが必要ない「Python・PHP系」
シングルクオート・ダブルクオートに関係なくエスケープが必要な「Javascript・ActionScript系」
の3通りが存在しているようだ。
なお、上記の調査方法ですが、RubyとPythonは対話モードで直接、PHPは下記コードを実行して調べてます。
<?php
$dot = '..';
if(ereg('^(\.){1,2}$', $dot)){ echo "success1\n"; }
if(ereg("^(\.){1,2}$", $dot)){ echo "success2\n"; }
$str = 'ab';
if(ereg('^(\.){1,2}$', $str)){ echo "error1\n"; }
if(ereg("^(\.){1,2}$", $str)){ echo "error2\n"; }
echo "\n";
?>
ActionScriptはステージ直下に下記スクリプトを書いて調査。
var dot:String = '..';
var str:String = 'ab';
// 「..」にはマッチして欲しい => alertが出ないとエラー
if( dot.match(new RegExp('^(\.){1,2}$')) ) trace('success 1');
if( dot.match(new RegExp('^(\\.){1,2}$')) ) trace('success 2');
if( dot.match(new RegExp(/^(\.){1,2}$/)) ) trace('success 3');
if( dot.match(/^(\.){1,2}$/) ) trace('success 4');
// 「ab」にはマッチして欲しくない => alertが出たらエラー
if( str.match(new RegExp('^(\.){1,2}$')) ) trace('error 1'); //=> NG
if( str.match(new RegExp('^(\\.){1,2}$')) ) trace('error 2');
if( str.match(new RegExp(/^(\.){1,2}$/)) ) trace('error 3');
if( str.match(/^(\.){1,2}$/) ) trace('error 4');
Perlは調べてないけど、ドキュメント見てる限りPHPのPythonの挙動に近そうではある。ここに出てない言語についても、良かったら誰か調べて教えて下さい!
Ruby, JavaScript, ActionScript, PHP, Python, 正規表現 |
comments(1) |
trackbacks(1)
2009.04.07 Tue 22:38
TRACKBACKS
- Casino 1250541813 - Casino 1250541813
- Casino 1250541813
この記事へのトラックバックURL: http://www.red-mount.com/trackback/40_ac9ccaaf35524e2ac5f2e2bfa6cbaded14e4f54d
ABOUT ME
tak (Takahito Sezutsu)
コメント、トラックバックはお気軽に!
COMMENTS
-
Beanstalk - WEBで管理可能なフリーのSubversionサーバー
→LILAC (08.14) -
CSS Nite in Ginza Vol.29に行ってきました。
→Betsy (05.14) -
「オリジナルの項目が見つからなかったので、エイリアス“********”は開けません。」と出て、Finderで外付けHDDが開けない時は
→poo (04.19) -
MacのSkypeでログイン時プルダウンメニューに表示されるSkype名を消す方法
→tak (06.22) -
「オリジナルの項目が見つからなかったので、エイリアス“********”は開けません。」と出て、Finderで外付けHDDが開けない時は
→tak (06.22) -
「オリジナルの項目が見つからなかったので、エイリアス“********”は開けません。」と出て、Finderで外付けHDDが開けない時は
→ko (06.22) -
MacのSkypeでログイン時プルダウンメニューに表示されるSkype名を消す方法
→Mac (05.06) -
MacのSkypeでログイン時プルダウンメニューに表示されるSkype名を消す方法
→tak (03.11) -
MacのSkypeでログイン時プルダウンメニューに表示されるSkype名を消す方法
→tama (03.11) -
Mac版ATOK定額制(体験版)を1週間使ってみた
→tak (09.19)
COMMENTS
いろいろやってると混乱します。まで読んだ。