Top > Programming > Ruby > Difference between Regexp.new and slash pattern
Last-modified: Fri, 04 Apr 2014 01:36:54 JST
Counter:2303 Today:2 Yesterday:1 Online:6
このエントリーをはてなブックマークに追加

Regexp.new("pattern") と /pattern/ の違い

この項目の内容は、Ruby 2.0.0 と Ruby 2.1.1 で検証しています。

多くのサイト(公式含む)では Regexp.new によってインスタンス化される正規表現オブジェクトと、/pattern/ によってインスタンス化される正規表現オブジェクトが同等である、と述べられています。結果的に得られるインスタンスが同等の機能を果たすかどうか、という観点では正しいのですが、与えるパターンによって、生成される正規表現オブジェクトに違いが現れます。

重要な違いとして、Regexp.new("pattern") の場合、一部の記号(メタ文字)のエスケープは2回必要になります。一方で、/pattern/ の場合には、エスケープは1回で良いです。多くの Ruby のテキスト、あるいはWeb の記事は、このことについて言及されていません。また、Regex.new(/pattern/) の場合には、/pattern/ と同じ挙動をします。つまりエスケープは1回で良いです。

2回のエスケープが必要な記号によっては、正規表現のコンパイルエラーや正規表現オブジェクトの挙動が変動する点にも注意する必要があります。次の記号は、1回だけエスケープすると、正規表現のコンパイルエラーが起きる記号です。これらのコンパイルエラーを解決するには、エスケープ記号を1つ増やします。

    # エラーが起きる記号
    regex = Regexp.new("\+")
    regex = Regexp.new("\(")
    regex = Regexp.new("\*")
    regex = Regexp.new("\\")
    regex = Regexp.new("\?")
    regex = Regexp.new("\)")
    regex = Regexp.new("\[")

次の記号は、コンパイルエラーが発生しないものの、文字列としての記号(リテラル文字)ではなく、正規表現としての記号(メタ文字)として扱われます。最も気を付けなければいけないパターンです。

    regex = Regexp.new("\.") #. の正規表現構文と同じ動きになる。
    regex = Regexp.new("\|") #| の正規表現構文と同じ動きになる。

また記号だけではなく、\A や \z などの一部の特殊なパターン(メタ文字)も、2回エスケープの必要があります。コンパイルエラーにはなりませんが、期待した結果が得られません。

    regex = Regexp.new("\A")
    regex = Regexp.new("\z")

更に特殊なパターンも存在します。"[" 記号は2回エスケープが必要になる記号ですが、一方で、対になる "]" 記号はエスケープが1回でも見かけ上は良いです。ただし、コンパイルと実行時に "(warning: regular expression has ']' without escape: /\[]/)" が表示されます。この問題を解決するには、"]" 記号も2回エスケープします。

    regex = Regexp.new("\\[\]") #警告が出る
    regex = Regexp.new("\\[\\]") #警告が出ない

これ以外の主な記号(次の記号)は、1回のエスケープで期待した通りの挙動になります。ただしすべてを確かに検証したわけではないので、もしもコンパイルできなかったり、期待した結果が得られないときは、この問題を疑うべきです。

    regex = Regexp.new("\-")
    regex = Regexp.new("\$")
    regex = Regexp.new("\@")
    regex = Regexp.new("\]")