9027


  1. かっこ`[]`で囲まれた文字以外を取得
  2. 取得した文字列を加工
  3. 加工した文字列に置き換える

例

`"[ほげ]あいうえお[ふが]かきくけこ"`

↓

`"[ほげ]<あいうえお>[ふが]<かきくけこ>"`

このような処理をrubyで行いたいのですがどうやったらよいのでしょうか。  
どの様な関数を使って処理するのかまったくイメージがつかめません・・・


CC BY-SA 3.0
2015-04-10T14:55:39.660
9021
2015-04-11T06:34:00.663
2015-04-11T06:34:00.663
49
5855
question
ruby
括弧[]で囲まれない全ての部分文字列を置換したい


こんな感じでどうでしょうか。  
[ ]で囲まれる部分とそうでない部分をマッチさせて、  
[で始まるものはそのまま、そうで無いものは<>で囲みます。

[code]

    p "[ほげ]あいうえお[ふが]かきくけこ".gsub(/((\[.+?\])|(?!\[)([^\[\]]+))/){ $1[0] =='[' ? $1 : '<' + $1 + '>' }#/((\[[^\]]+\])|([^\[\]]+))/
    
[/code]


CC BY-SA 3.0
2015-04-10T15:48:13.237
9027
2015-04-10T19:12:05.203
2015-04-10T19:12:05.203
5044
5044
9021
answer


私も挑戦してみました。

[code]

    def f(t)
      t.gsub(/(^|\])([^\]]+?)(\[|$)/,'\1<\2>\3')
    end
    
    puts f("[ほげ]あいうえお[ふが]かきくけこ")
    puts f("あいうえお[ほげ]かきくけこ[ふが]")
    puts f("[ほげ]あいうえおかきくけこ[ふが]")
    puts f("あいうえお[ほげ][ふが]かきくけこ")
    
[/code]


CC BY-SA 3.0
2015-04-10T17:07:58.843
9029
2015-04-11T01:55:23.193
2015-04-11T01:55:23.193
7900
7900
9021
answer


`<>`で囲む文字列は、

  * 行頭か`]`の後から始まる
  * `[`を含まない文字列
  * `[`か行末の前で終わる

という特徴があるので、それを正規表現で表すと次のようになります

[code]

    puts "[ほげ]あいうえお[ふが]かきくけこ".gsub(/(?<=^|\])([^\[]+)(?=\[|$)/, '<\1>')
    
[/code]


CC BY-SA 3.0
2015-04-11T01:03:06.777
9035
2015-04-11T01:03:06.777
7414
9021
answer


HTML/XML同様、入れ子になる可能性のある文章に正規表現を使ってはダメです。

[code]

    orig = "[ほげ]あいうえお[ふが]かきくけこ"
    
    nest = 0
    ar = []
    orig.split(/\b/).each do |token|
        change_nest = token === '[' ?  1
                    : token === ']' ? -1 
                    :                  0;
    
        nest += change_nest;
    
        if change_nest != 0 then
            ar.push(token)
            next
        end
    
        if nest != 0 then
            ar.push(token)
            next
        end
    
        ar.push("<#{token}>")
    end
    
    p ar.join()
    
[/code]


CC BY-SA 3.0
2015-04-11T03:17:01.007
9039
2015-04-11T03:17:01.007
62
9021
answer


全部正規表現で対応しようと思うと正規表現が複雑になって保守性が悪くなりそうな気がしました。  
なので、"[ほげ]"のような部分だけを抜き出す正規表現を使い、あとはRuby側で文字列処理を行うようにしてみました。

[code]

    def surround_with_angle_brackets(string)
      regex = /(\[.*?\])/
      words = string.split(regex)
      words.reject(&:empty?).map{|w| w =~ regex ? w : "<#{w}>" }.join
    end
    
[/code]

あと、テストコードも書いて質問以外のパターンでも動作確認しています。

[code]

    require 'minitest/autorun'
    
    class TestSurroundWithAngleBrackets < Minitest::Test
      def surround_with_angle_brackets(string)
        regex = /(\[.*?\])/
        words = string.split(regex)
        words.reject(&:empty?).map{|w| w =~ regex ? w : "<#{w}>" }.join
      end
    
      def test_surround_with_angle_brackets
        # 質問と同じ
        assert_equal '[ほげ]<あいうえお>[ふが]<かきくけこ>', surround_with_angle_brackets('[ほげ]あいうえお[ふが]かきくけこ')
        # []が連続する場合
        assert_equal '[ほげ]<あいうえお>[ふが][ふが]<かきくけこ>', surround_with_angle_brackets('[ほげ]あいうえお[ふが][ふが]かきくけこ')
        # []以外で始まり、[]で終わる場合
        assert_equal '<あいうえお>[ふが]<かきくけこ>[ほげ]', surround_with_angle_brackets('あいうえお[ふが]かきくけこ[ほげ]')
        # []がない場合
        assert_equal '<あいうえお>', surround_with_angle_brackets('あいうえお')
        # すべて[]の場合
        assert_equal '[ほげ][ふが]', surround_with_angle_brackets('[ほげ][ふが]')
        # 文字列が空の場合
        assert_equal '', surround_with_angle_brackets('')
      end
    end
    
[/code]

よかったら参考にしてみてください。


CC BY-SA 3.0
2015-04-11T03:19:17.513
9040
2015-04-11T03:27:18.367
2015-04-11T03:27:18.367
85
85
9021
answer