正規表現でマッチした文字列だけすぐほしいとき
結論
マッチデータ全体がほしいとき
/Regexp/=~str&&$&
部分がほしいときには
/Regexp/=~str&&$n
恥
マッチが失敗することを考慮するときにはto_a[1]を投げれば良かったんじゃないか
でも、短いしperlでも使える。よしとしよう。
$ perl -e 'print "abc"=~/./&&$&,"\n"' a $ perl -e 'print "abc"=~/d/&&$&,"\n"'
説明
まあ、通常は=~つかってマッチさせて$&と$数字でマッチした文字列を得ると思う。
irb(main):001:0> 'abc'=~/.(.)/ => 0 irb(main):002:0> $& => "ab" irb(main):003:0> $1 => "b"
注意:perlは=~が逆だと動かない。
正規表現オブジェクトにmatchメソッドを投げればMatchDataオブジェクトが返ってくるのでそれを利用することもできる。
irb(main):004:0> /.(.)/.match('abc') => #<MatchData:0x7ffa1ad4> irb(main):005:0> /.(.)/.match('abc')[0] => "ab" irb(main):006:0> /.(.)/.match('abc')[1] => "b"
ところが、マッチしない場合には[0],[1]はエラーとなってしまう。
irb(main):007:0> /d/.match('abc')[0] NoMethodError: undefined method `[]' for nil:NilClass from (irb):7 from :0 irb(main):008:0> /d(.)/.match('abc')[1] NoMethodError: undefined method `[]' for nil:NilClass from (irb):8 from :0
ここで[0]の時には返ってくるMatchDataオブジェクトにto_sを投げればnilにto_sに投げることと同じになるのでいけるのだが、[1]の時にはそうはいかない。
irb(main):009:0> /d/.match('abc').to_s => "" irb(main):010:0> /./.match('abc').to_s => "a"
そこで両方に共通な書き方がないかと考えてみたところ、考えついたのが /正規表現/=~マッチ対象&&$& だ。
別段大したことないのだが、記述量が小さいのがいける。(またかよ)
irb(main):011:0> /.(.)/=~'abc'&&$& => "ab" irb(main):012:0> /.(.)/=~'abc'&&$1 => "b" irb(main):013:0> /d(.)/=~'abc'&&$& => nil irb(main):014:0> /d(.)/=~'abc'&&$1 => nil
以上のように match().to_sよりも7文字削減する効果もある。
Arrayオブジェクトにもの申す
irb(main):001:0> [1,2,3][3] => nil
何故、例外を起こさない!!*1
と、いうことで例外を起こすようにArray#[]を再定義してみる。
#!/usr/bin/ruby class Array def [](i) raise IndexError unless self.size>i.abs self.at(i) end end a=Array[1,2,3] puts a[0] # =>1 puts a[2] # =>3 puts a[3] # =>IndexError
まあ、Array#atを使った時点で負け犬か(涙
追記11/16 : http://d.hatena.ne.jp/n9d/20071116 へ書き直した
*1:ただ単に 上の記事のto_aが悔しかっただけともいう
例外が怒っても安心して終了するには
例外の書き方
begin raise if ... ... raise "a" resuce 例外クラス ...処理 rescue 例外クラス ...処理 rescue ....上の例外以外のもの時実行される else ....例外が起きなかったとき実行される ensure ...最期に必ず事項される。(後処理) end
getsとちがいreadlineはEOF時に例外を出力する。これを利用するとこんなのが書ける。この辺はマニュアルがすごくわかりづらい。
begin while true puts readline end rescue EOFError puts "EOF" end
例外を複数キャプチャーその1
begin while true raise "STOP" if readline =~/stop/ puts $_ end rescue EOFError puts "EOF" rescue RuntimeError puts $! end
例外を複数キャプチャーその2
begin while true raise "STOP" if readline =~/stop/ puts $_ end rescue EOFError puts "EOF" rescue puts $! end
実行結果
$ ./exception.rb foo foo bar bar EOF $ ./exception.rb foo foo stop STOP