Tech Racho エンジニアの「?」を「!」に。
  • 開発

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. '\'(バックスラッシュとクォート、後方参照なし)に置き換えたい場合は、'\\\\\''を置き換え文字列とします。 

CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。