akishin999の日記

調べた事などを書いて行きます。

Ruby 1.9 の正規表現の名前付きキャプチャ

Ruby 1.9正規表現では名前付きキャプチャが使えるそうなので、いまさらですがちょっと試してみました。

適当なサンプルを思いつかなかったので、とりあえず Apache の Common Log Format 文字列を分解してみます。
正規表現が若干適当なのは名前付きキャプチャのサンプルということで・・・^^;

# Apache の Common Log Format 文字列
logs = [
  '192.168.0.2 - - [16/Feb/2012:07:26:55 +0900] "GET / HTTP/1.1" 200 4597',
  '192.168.0.2 - - [16/Feb/2012:07:26:53 +0900] "GET /board/list HTTP/1.1" 200 5240',
  '192.168.0.2 - - [16/Feb/2012:07:26:49 +0900] "GET /javascripts/application.js?1322293379 HTTP/1.1" 304 -',
]

# 正規表現を左に書くと名前付きキャプチャと同名のローカル変数が自動で定義される
logs.each {|line|
  if /(?<ipaddress>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})[\s-]+\[(?<date>\d+\/\w+\/\d+:\d+:\d+:\d+.*\+\d+)\]\s"(?<method>\w+)\s[\w\/\.\?]+\s(?<protocol>[\w\/\.]+)"\s(?<status>\d+)/ =~ line
    p ipaddress
    p date
    p method
    p protocol
    p status
  end
}


# 文字列を左に書くとローカル変数は定義されず、$~ に名前をキーにして格納される
logs.each {|line|
  if line =~ /(?<ipaddress>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})[\s-]+\[(?<date>\d+\/\w+\/\d+:\d+:\d+:\d+.*\+\d+)\]\s"(?<method>\w+)\s[\w\/\.\?]+\s(?<protocol>[\w\/\.]+)"\s(?<status>\d+)/
    p $~[:ipaddress]
    p $~[:date]
    p $~[:method]
    p $~[:protocol]
    p $~[:status]
  end
}


正規表現文字列は名前付きキャプチャを使った方が若干長くなりますが、その分マッチした後のソースコードの可読性は上がると思うので、個人的には $1 などで参照するよりはお気に入りです。

ただし、正規表現文字列を左側に書いた場合のみローカル変数が自動で定義されたり、左側に正規表現を書く場合でも、変数や定数に格納してある正規表現の場合には変数定義されない、といったあたりの挙動は分かりづらいので注意が必要ですね。

参考

Ruby Freaks Lounge:第5回 Ruby 1.9 の新機能ひとめぐり(後編): 知っておくとお得な機能|gihyo.jp … 技術評論社
http://gihyo.jp/dev/serial/01/ruby/0005

Ruby 1.9 の新機能もうひとめぐり (後編) - まめめも
http://d.hatena.ne.jp/ku-ma-me/20090331/p1