概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Idiosyncratic Ruby: Escape Back Referencing
- 原文公開日: 2017/12/25
- 著者: Jan Lelis
- サイト: Idiosyncratic Ruby
Ruby: 正規表現の後方参照を「正しく」エスケープする方法(翻訳)
Rubyには、直近の正規表現マッチの追加情報(グループキャプチャなど)にアクセスする方法がいくつもあります。ドル記号$
付きの$`
や$&
や$'
や$1
〜$9
や$+
などの特殊変数を用いる方法もあれば、MatchData
オブジェクト$~
を使う方法もあります。これらは、正規表現にマッチしたメソッドを使った後に利用可能になります。また、メソッドがブロックをサポートしていれば、そのブロック内で既に利用できます。
しかし、文字列置き換えメソッドであるString#gsub
やString#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" |
$1 2 |
'\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" |
---|---|---|---|---|---|---|---|
& |
マッチ | マッチ | "\\&" |
"&" |
マッチ | マッチ | "\\&" |
` |
マッチ直前の文字 | マッチ直前の文字 | "\\`" |
"`" |
マッチ直前の文字 | マッチ直前の文字 | "\\`" |
' |
"'" |
- | マッチ直後の文字 | "'" |
マッチ直後の文字 | マッチ直後の文字 | "\\'" |
0 1 |
マッチ | マッチ | "\\0" |
"\u0000" |
マッチ | "\\\u0000" |
"\\0" |
1 2 |
1番目のキャプチャ | 1番目のキャプチャ | "\\1" |
"\u0001" |
1番目のキャプチャ | "\\\u0001" |
"\\1" |
+ |
最後のキャプチャ | 最後のキャプチャ | "\\+" |
"+" |
最後のキャプチャ | 最後のキャプチャ | "\\+" |
k<name> |
名前付きキャプチャ | 名前付きキャプチャ | "\\k<name>" |
"k<name>" |
名前付きキャプチャ | 名前付きキャプチャ | "\\k<name>" |
訳注: 上のエスケープをRuby 2.5.1で確認しました。