Rubyには、$1, $2, $3 ...
という特殊変数があり、$n
には最後に成功したパターンマッチで n 番目の括弧にマッチした値が代入されます。
"abc" =~ /(.)(.)(.)/
p $1 #=> "a"
p $2 #=> "b"
p $3 #=> "c"
番号 n はいくらでも大きな正整数を利用できます。
とありますが、実際には超巨大な値を使おうとすると、warningが表示されます (遊んでいるときに気が付いた)
$ ruby -e '$9999999999999999'
-e:1: warning: `$9999999999999999' is too big for a number variable, always nil
こうなると$n
のnとしてどれだけの値が使えるのか気になってくるので、簡単な二分探索を使った以下のコードで調べてみたところ、自分の環境では最大値は1073741823のようでした。
require 'stringio'
ok = 0
ng = 10**10
while (ok-ng).abs > 1
io = StringIO.new
$stderr = io
mi = (ok+ng)/2
eval("$#{mi}")
if io.size == 0
ok = mi
else
ng = mi
end
$stderr = STDERR
end
p ok #=> 1073741823
別の方法で確認してみても、$1073741823
が最大で、それよりも大きい値になると警告がでるようです。ただ1073741823という値はいかにも環境依存っぽいので、環境によってはもっと大きい値まで使えるかもしれませんし、もっと小さい値で警告が出てくるかもしれません。
$ ruby -e '$1073741823'
# => 何も起きない
$ ruby -e '$1073741824'
# => 警告が出力される
# => -e:1: warning: `$1073741824' is too big for a number variable, always nil
当然の疑問として、キャプチャ数が1073741823個を超える正規表現でマッチが成功した場合どうなるのかということですが、これは無問題。Rubyではキャプチャ数の上限が32767と決まっており、それを超えるような正規表現はコンパイルに失敗します。
$ ruby -e 'Regexp.compile("(.)"*32767)'
# => 何も起きない
$ ruby -e 'Regexp.compile("(.)"*32768)'
# => RegexpErrorが発生する。メッセージは次の通り
# => `initialize': too many capture groups are specified:
自分は以下のような二分探索を用いた簡単なスクリプトで32767という値を見つけましたが、Rubyの正規表現エンジンである鬼雲のソースコードを見ると、ONIG_MAX_CAPTURE_GROUP_NUM
というキャプチャ数の上限を示す変数があって、これが32767になっているようです。 であれば、特殊変数$1, $2, $3 ...
の側の最大値を32767にしてもよいような気はしますが(´・ω・`)
ok = 0
ng = 10**8
while (ok-ng).abs > 1
mi = (ok+ng)/2
begin
Regexp.compile("(.)"*mi)
ok = mi
rescue RegexpError => e
ng = mi
end
end
p ok #=> 32767
環境情報
$ ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]