MAGAZINE

ルーターマガジン

Ruby

【ruby】Stringをrefinementしてテキスト処理

2018.12.12
Pocket

こんにちは。エンジニアのTakahashiです。
スクレイピングしたとき、いらない文字までとってきてしまうことがよくあります。

name = "テ ス ト 太 郎"
age = "2 0 才"

上の例ではスペースが不要に見えます。
gsubメソッドで消してしまいましょう。

name = "テ ス ト 太 郎"
age = "2 0 才"

puts name.gsub(/[[:space:]]/,"")
puts age.gsub(/[[:space:]]/,"")
# >>テスト太郎
# >>20

こんな感じでしょうか。/[[:space:]]/はスペースを指定する正規表現で、ノンブレーキングスペース等も指定できます。


gsubこぼれ話

gsubは、文字列を置換するメソッドです。第一引数に置換対象文字列・第二引数に置換後の文字列を指定します。第一引数には、文字列だけでなく正規表現も指定できます。
subメソッドによく似ていますが、subメソッドは1番最初にヒットした要素を置換/gsubメソッドはヒットした全要素を置換するという違いがあります。
そんなgsubですが、ブロックも引数に指定できるということを最近知りました。

numbers = "1 2 3 4 5"

replaced = numbers.gsub(/\d/) do |num|
  if num.to_i.odd?
    "odd"
  else
    "even"
  end
end

puts replaced
# >>odd even odd even odd

引数にヒットした文字列を、ブロックの戻り値に置換します。複雑な条件の置換を行う場合に重宝しそうです。(ブロックの中にif文を書くかかブロックの外に書くかの違いですね・・gsubを使うのが1回で済むのがこちらのメリットでしょうか。このブロックつきgsubが必須なシチュエーションはなさそうです)


長くなってしまいましたが、元のスペース削除の話に戻ります。DRY原則に則って処理を共通化してみましょう。

def rm_space(target)
  target.gsub(/[[:space:]]/,"")
end

name = "テ ス ト 太 郎"
age = "2 0 才"

puts rm_space(name)
puts rm_space(age)
# >>テスト太郎
# >>20

あと、StringをStringに変換していますから、Stringのインスタンスメソッドとしたらより自然なのではないでしょうか。

class String
  def rm_space
    self.gsub(/[[:space:]]/, "")
  end
end

name = "テ ス ト 太 郎"
age = "2 0 才"

puts name.rm_space
puts age.rm_space
# >>テスト太郎
# >>20才

個人差あるかもしれませんが私はこちらのほうが好みです。

ただ、標準クラスのStringを書き換える行為はモンキーパッチと呼ばれます。この程度では不具合は起きませんが、既存のコアな機能を書き換えると思わぬところで不具合が起きることもあり、忌み嫌われる傾向があるようです。

この対策として、rubyの標準機能であるrefinementを使用すると、モンキーパッチの影響範囲を限定できます。
refinementでは、モンキーパッチの有効範囲はusingを使用したモジュール/クラス内。トップレベルで使用したらそのファイルの最後の行までと、汚染が少なくなります。
refinementを使った実装が以下になります。

module UtilExtention
  refine String do
    def rm_space
      self.gsub(/[[:space:]]/, "")
    end

    def rm_punct
      self.gsub(/[[:punct:]]/,"").gsub(/[●■]/,"")
    end

  end
end

using UtilExtention

name = "テ ス ト 太 郎"
age = "2 0 才"

puts name.rm_space
puts age.rm_space
# >>テスト太郎
# >>20

UtilExtentionに、スペースの削除に加えて、よく使いそうな、記号の削除を追加してみました。(/[[:punct:]]/は多くの記号にヒットしますが、●■等にはヒットしません。これらは個別に指定して削除しています)

よく使うメソッドはrefimementに持っておくと便利かつ安心かもしれません。

Pocket

CONTACT

お問い合わせ・ご依頼はこちらから