Ruby
正規表現

MatchData#[]の引数について

More than 3 years have passed since last update.

MatchData#[]の引数について

Rubyの正規表現におけるキャプチャについてドキュメントを見てみると

丸括弧 ( ) によってキャプチャをすることができます。 括弧に囲まれた部分正規表現にマッチした 前からn番目の開き括弧によって囲まれた部分式にマッチした 文字列を後で参照することができます。

正規表現内では \1, \2, ... という記法で後方参照できます。 また、\k<1>, \k<2>, ... や \k'1', \k'2', ... という記法を使うこと もできます(10を越える数字を渡すことができます)。 また、Regexp#match で得られた MatchData からは MatchData#[]で取り出せます。
また、\$1, \$2, ... という特殊変数によって n 番目の括弧にマッチした 部分文字列を参照できます。これらの特殊変数はマッチ処理が終わったあとで しか使えないことに注意してください。

# (..) に at がマッチしたのを \1 で参照し、マッチが成功している。
m = /[csh](..) [csh]\1 in/.match("The cat sat in the hat")
# => #<MatchData "cat sat in" 1:"at">
# Regexp#match でマッチしたテキストは MatchData#[] で参照できる
m[1] # => "at"

しかしこの例では、m[1]がどのatを指しているのか非常に分かりづらいです。
結論から申し上げると、1番最初に出てくるcatのatです。
MatchData#[]はn番目のカッコにマッチした部分文字列を取り出す場合nを引数に渡してあげる必要があります。n-1ではありません。
では0は何を指すのでしょう。0はマッチした文字列の全体を指します。

match_test.rb
m = /\[(.*)\] (.*)\: (.*)/.match("[12:34] Alice: Hello")
p m[1] # => "12:34"
p m[0] # => "[12:34] Alice: Hello"
output
$ ruby match_test.rb 
"12:34"
"[12:34] Alice: Hello"