String#[]の括弧内に正規表現

Rubyベストプラクティス -プロフェッショナルによるコードとテクニック

Rubyベストプラクティス -プロフェッショナルによるコードとテクニック

を読んでいたら、String#[/正規表現/, 1]という表記がしょっちゅう出てきた。には出てこない表記なので調べた。

instance method String#[]

self[regexp, nth = 0] -> String
slice(regexp, nth = 0) -> String

正規表現 regexp の nth 番目の括弧にマッチする最初の部分文字列を返します。 nth を省略したときや 0 の場合は正規表現がマッチした部分文字列全体を返します。 正規表現が self にマッチしなかった場合や nth に対応する括弧がないときは nil を返します。
このメソッドを実行すると、 マッチ結果に関する情報が組み込み変数 $~ に設定されます。

取得したい文字列のパターンを示す正規表現

  • [PARAM] nth:

取得したい正規表現レジスタのインデックス。整数

p "foobar"[/bar/]  # => "bar"

p $~.begin(0)      # => 3 *1

p "def getcnt(line)"[ /def\s+(\w+)/, 1 ]   # => "getcnt"

instance method String#[] (Ruby 1.9.3)

なるほど。
マッチした部分を取るのはString#[/正規表現/]でいけるのね。
String#scanだとこうなる。

instance method String#scan

scan(re) -> [String] | String

self に対して正規表現 re を繰り返しマッチし、 マッチした部分文字列の配列を返します。
正規表現が括弧を含む場合は、 括弧で括られたパターンにマッチした部分文字列の配列の配列を返します。
例:

p "foobar".scan(/../)               # => ["fo", "ob", "ar"]
p "foobarbazfoobarbaz".scan(/ba./)  # => ["bar", "baz", "bar", "baz"]

p "foobar".scan(/(.)/)
    # => [["f"], ["o"], ["o"], ["b"], ["a"], ["r"]]

p "foobarbazfoobarbaz".scan(/(ba)(.)/)
    # => [["ba", "r"], ["ba", "z"], ["ba", "r"], ["ba", "z"]]

instance method String#scan (Ruby 1.9.3)

使い分けできそうですね。String#scanだと必ず配列に入るので、文字列へ戻すのに[0][0]とか付けたりするのが面倒だったんですよ。

何番目じゃなく名前を付けて指定

?<名前>と表記することで正規表現を指定できる。

self[regexp, name] -> String
slice(regexp, name) -> String
正規表現 regexp の name で指定した名前付きキャプチャにマッチする最初の 部分文字列を返します。正規表現が self にマッチしなかった場合は nil を返 します。

[PARAM] regexp:
正規表現を指定します。
[PARAM] name:
取得したい部分文字列のパターンを示す正規表現レジスタを示す名前
[EXCEPTION] IndexError:
name に対応する括弧がない場合に発生します。
例:

s = "FooBar"
s[/(?[A-Z]..)(?[A-Z]..)/]        # => "FooBar"
s[/(?[A-Z]..)(?[A-Z]..)/, "foo"] # => "Foo"
s[/(?[A-Z]..)(?[A-Z]..)/, "bar"] # => "Bar"
s[/(?[A-Z]..)(?[A-Z]..)/, "baz"] # => IndexError

instance method String#[] (Ruby 1.9.3)

便利だけど…逆に読みづらいかも。

*1:$~.begin(0)は0番目のマッチの開始位置。$~.end(0)だと0番目のマッチの終了位置