2014年9月17日水曜日

Rubyで文字数を指定して文字列を分割

Rubyで文字数を指定して文字列を分割したいって思ったのでちょっと調べたらいろいろ勉強になった。ので、そのメモです。

余談ですが、どうしてそんなことしようとしたのかというと、TwitterBotに投稿させるとき、内容が140字オーバーしてたら分割して投稿するようにしたかったからです。


調べたら答えは出てきたのですが、
1
2
3
4
s = "1234567890"
n = 3
s.scan(/.{1,#{n}}/)
# => ["123", "456", "789", "0"]
パっと見理解できなかったので、ひとつひとつ見ていきます。

scanメソッド

まず、scanメソッドというのは、

「引数で指定した正規表現のパターンとマッチする部分を文字列からすべて取り出し、配列にして返すメソッド」

だそうです。→str.scan(pattern)より。
つまり、条件に合うやつがひとつひとつ配列の要素になる的な。


任意の文字にマッチさせる

ではその条件というのはどう指定すればいいのでしょうか。
自分は「指定した文字数で分割していって一番最後の要素はそれ以下でもよい」って感じにしたいです。

Rubyがサポートしてる正規表現のメタ文字において、"."は「改行を除く任意の1文字」にマッチします。しかし、Twitterの投稿において改行(\n)も1文字として数えられるので改行にもマッチしてほしい…。

そのために正規表現に対してオプションを指定します。
1
2
p "\n".match(/./)  # => nil
p "\n".match(/./m) # => #<MatchData "\n">
"/"の直後の文字によってオプションを指定でき、"m"は複数行モードでその能力は
正規表現 "." が改行にもマッチするようになるッ!!」です。

繰り返しで分割文字数指定

あとは"."がどれくらい繰り返されるかを指定すれば分割できそうですね。
範囲指定繰り返し制御は"{}"を使います。
1
2
3
p "aaaa".match(/.{1}/)   # => #<MatchData "a">    1回
p "aaaa".match(/.{1,}/)  # => #<MatchData "aaaa"> 1回以上
p "aaaa".match(/.{1,3}/) # => #<MatchData "aaa">  1回以上最大3回
140字以内で1文字以上としたいので"{1,140}"とすればよさそうです。


終わりに
1
post_text.scan(/.{1,140}/m)
とすれば「改行を含む140字以上の文字列を、140字ずつ分割して配列の要素にし、最後の要素は140字以下のものでもよい」って感じになるわけですね。

正規表現って難しい…。

参考サイト
Ruby 文字列を任意の文字数に分割する

0 件のコメント:

コメントを投稿