LoginSignup
2
1

More than 3 years have passed since last update.

特殊変数$1, $2, $3 ... で巨大な整数を使おうとすると、警告が表示される

Posted at

Rubyには、$1, $2, $3 ...という特殊変数があり、$nには最後に成功したパターンマッチで n 番目の括弧にマッチした値が代入されます。

"abc" =~ /(.)(.)(.)/
p $1 #=> "a"
p $2 #=> "b"
p $3 #=> "c"

2020/09/26現在のるりまには

番号 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]
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1