MAGAZINE
ルーターマガジン
【ruby】Stringをrefinementしてテキスト処理
こんにちは。エンジニアの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に持っておくと便利かつ安心かもしれません。
CONTACT
お問い合わせ・ご依頼はこちらから