From: "Y. NOBUOKA" Date: 2011-04-29T00:13:34+09:00 Subject: [ruby-list:48017] Re: 文字列を正規表現にマッチする部分と他の部分に分割 5.5 さん 信岡です。 > 文字列 S の中で,正規表現 R にマッチする部分とそれ以外の > 部分をそれぞれ取得したいときに,どうもうまい方法が見つか > りません。 正規表現でマッチした部分や、マッチした部分の前の部分、 後の部分を取得するための変数として、以下のものがあります。 マッチした部分 : $& 前の部分 : $` 後の部分 : $' irb(main):025:0> 'abcdefg,test' =~ /,/ => 7 irb(main):026:0> "マッチ部分 : #{$&}" => "マッチ部分 : ," irb(main):027:0> "前の部分 : #{$`}" => "前の部分 : abcdefg" irb(main):028:0> "後の部分 : #{$'}" => "後の部分 : test" これを用いれば、単純な while ループで望みの動作を得られます。 result = '' str = 'ab12cd' while true do i = ( str =~ /\d+/ ) result << $`.upcase << "<#{$&}>" str = $' end result << str #=> "AB<12>CD" ただ、5.5 さんの書かれた StringScanner での例と同じように 非マッチ文字列に対する処理が 2 箇所に書かれているという 問題があります。 そこで、自分で新たに String#each_segment メソッドを定義する なら、以下のようになります。 class String def each_segment( regexp ) str = self while str =~ regexp do yield( $`, false ) yield( $&, true ) str = $' end yield( str, false ) end end result="" "343ab12cd534".each_segment /\d+/ do |str, match| result << (match ? "<#{str}>" : str.upcase) end result => "<343>AB<12>CD<534>" > マッチ部分とそれ以外の部分を取り出すには,String#split > に括弧付きの正規表現を与える方法もありますが, > > "ab12cd".split(/(\d+)/) # => ["ab", "12", "cd"] > > 正規表現中にグルーピングのための括弧があるとダメですし, > マッチ部分かそうでない部分かをもう一度判定しなければなり > ません。 正規表現中にグルーピングのための括弧があると、とのことですが、 グルーピングにはグルーピングのための記法 ("(?:XXX)" の形式) が あるので、これを用いれば問題にはならないと思います。 また、マッチ部分かそうでないかの判定は、結果の配列の偶数番目 か奇数番目かで判断すればいいのではないでしょうか? 偶数番目はマッチ部分、奇数番目はそれ以外、です。 irb(main):009:0> "1242faefa3423fae344".split( /(\d+)/, -1 ) => ["", "1242", "faefa", "3423", "fae", "344", ""] > 汎用性のあるもっとうまい書き方があるのか,それとも提案し > たようなメソッドの導入に意義があるのか,どんなものでしょ > うか。 私が思いつく限りでは、上で述べたような方法で望みの処理ができるのでは ないかと思います。 (もしかするともっといい方法があるかも。。) 自分で定義して使う分には、提案されたようなメソッドを定義するのも便利で 良いと思います。 参考になりましたら幸いです。 -- 信岡 ゆう (NOBUOKA Yu)