<< back to list

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系」
シングルクオート・ダブルクオートに関係なくエスケープが必要ないPythonPHP系」
シングルクオート・ダブルクオートに関係なくエスケープが必要な「JavascriptActionScript系」
の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)   このエントリーを含むはてなブックマーク Yahoo!ブックマークに登録 livedoor クリップに登録 del.icio.usに登録 Google Bookmarks に追加 この記事をBuzzurlに追加 2009.04.07 Tue 22:38

COMMENTS

15年経ってもCのfopenの引数を覚えない俺が来ましたよ。
いろいろやってると混乱します。まで読んだ。
posted by peixe    2009.04.08 Wed 08:34
name : email : url :  
captcha: simple_captcha.jpg(全て大文字のアルファベットです)
画像中の文字とおなじものを入力してください。
comment:
コメントには日本語を必ず入力してください。(スパム対策です)
COMMENT

TRACKBACKS

Casino 1250541813 - Casino 1250541813
Casino 1250541813

この記事へのトラックバックURL: http://www.red-mount.com/trackback/40_ac9ccaaf35524e2ac5f2e2bfa6cbaded14e4f54d

<< back to list
 

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)
フィードメーター - RED-MOUNT.COM
あわせて読みたいブログパーツ