Ruby: 正規表現の後方参照を「正しく」エスケープする方法(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Ruby: 正規表現の後方参照を「正しく」エスケープする方法(翻訳)

Rubyには、直近の正規表現マッチの追加情報(グループキャプチャなど)にアクセスする方法がいくつもあります。ドル記号$付きの$`$&$'$1$9$+などの特殊変数を用いる方法もあれば、MatchDataオブジェクト$~を使う方法もあります。これらは、正規表現にマッチしたメソッドを使った後に利用可能になります。また、メソッドがブロックをサポートしていれば、そのブロック内で既に利用できます。

しかし、文字列置き換えメソッドであるString#gsubString#subでもサポートされている特殊な文字列処理が存在します。ここで置き換えに用いられる文字列(2番目のパラメータ)には後方参照(back reference)を含められ、これは対応する特殊変数に似た振る舞いを示します。

"Idiosyncratic Ruby".sub(/(\w+) (\w+)/, '\2 \1') # => "Ruby Idiosyncratic"

訳注: 後方参照についてはMSDNの『後方参照』もどうぞ。

1. 正規表現の特殊変数と後方参照の対応関係

Perl的な記法 後方参照 動作
$& '\&''\0'1 マッチ "abc".gsub(/.*/, '\&\&') # => "abcabc"
$` '\`' マッチ直前の文字 "abc".gsub(/b/, '\`') # => "aac"
$' '\\\'' マッチ直後の文字 "abc".gsub(/b/, '\\\'') # => "acc"
$12 '\1' 1番目のキャプチャ "abc".gsub(/(a)b(c)/, '\1') # => "a"
$+ '\+' 最後のキャプチャ "abc".gsub(/(a)b(c)/, '\+') # => "c"
$~[:name] '\k<name>' 名前付きキャプチャ "abc".gsub(/(?<name>a)bc/, '\k<name>') # => "a"

2. エスケープについて

Rubyで後方参照そのものをエスケープしようとすると絶対的に混乱を招きます。文字列を一重引用符'で囲む場合は、バックスラッシュ\を1つまたは2つ使わなければなりません。文字列を二重引用符"で囲む場合はバックスラッシュを2つ(場合によっては3つ)使わなければなりません。\'のエスケープには特に注意が必要です3

訳注: 原文のbackspaceはbackslashの誤りと判断しました。

X '\X' '\\X' '\\\X' "\X" "\\X" "\\\X" "\\\\X"
& マッチ マッチ "\\&" "&" マッチ マッチ "\\&"
` マッチ直前の文字 マッチ直前の文字 "\\`" "`" マッチ直前の文字 マッチ直前の文字 "\\`"
' "'" マッチ直後の文字 "'" マッチ直後の文字 マッチ直後の文字 "\\'"
01 マッチ マッチ "\\0" "\u0000" マッチ "\\\u0000" "\\0"
12 1番目のキャプチャ 1番目のキャプチャ "\\1" "\u0001" 1番目のキャプチャ "\\\u0001" "\\1"
+ 最後のキャプチャ 最後のキャプチャ "\\+" "+" 最後のキャプチャ 最後のキャプチャ "\\+"
k<name> 名前付きキャプチャ 名前付きキャプチャ "\\k<name>" "k<name>" 名前付きキャプチャ 名前付きキャプチャ "\\k<name>"

訳注: 上のエスケープをRuby 2.5.1で確認しました。

関連記事

[Ruby] Kernelの特殊変数をできるだけ$記号なしで書いてみる


  1. $0は正規表現のマッチとは無関係であるにもかかわらず、\0は有効な後方参照です。 
  2. 「N番目のキャプチャ」も同様 
  3. '\'(バックスラッシュとクォート、後方参照なし)に置き換えたい場合は、'\\\\\''を置き換え文字列とします。 
デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ