図書館とか本の所持冊数で良く見るような見ないようなやつで
1-15,18,21-
というのがあると思います。
(こういうフォーマットて何か名前あるんでしょうか)
みたまんまと言いますか、これが何を表してるかっていうと
1から15巻、18巻、21巻以降を持っている(まだ未完)
とかまあそんな感じだと思います。
こういった文字列を Ruby の正規表現でチェックし、
実際にどの巻を持ってるか調べようかなとか思ったり。
決まりとして、
- 文字列の最初と最後は必ず数字で
- 今回は、「1-19,21-」みたいに、以降続刊とかいうのはなしで
- 「--」と続くのは弾く
- 「,」は連続でいくつ繋がっても無視する
てなことを決めると以下のような正規表現ができました。
(?!^[^\d]) => 文字列の先頭は数字以外認めない (?!.*[^\d]$) => 文字列の末尾は数字以外認めない (?!.*\,-) => 文中で「,-」と続くのは禁止 (?!.*-\,) => 文中で「-,」と続くのは禁止 (?!.*--) => 文中で「--」と続くのは禁止 [-\,\d]* => 以上の条件を踏まえた上で、 文字列は「-」「,」「数字」だけで構成される
(?!...)というのは否定先読み(negative lookahead)と呼ばれるものらしい。
こんな書き方初めてしった。奥が深いぜ正規表現
そんなこんなで、出来上がったのがこちら
str = "1-15,17,19,21-23" # 今回調べる文字列とする str = str.gsub(/\s/, "") if /^(?!^[^\d])(?!.*[^\d]$)(?!.*\,-)(?!.*-\,)(?!.*--)[-\,\d]*$/ =~ str array = str.split(',') array.each do |s| next if s.empty? # 「,」が連続である場合にひっかかる a = s.split('-') if a.length > 1 # ex. a = "3-6" => (3..6).to_a vol.concat((a[0].to_i..a[1].to_i).to_a) else vol << a[0].to_i end end vol.uniq! vol.sort! print vol.join(' ') end
これを実行すると
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 17 19 21 22 23
なんとかできてるっぽい。
指定した文字列中で重複した文字があったり
順番とかばらばらでも、最後に uniq や sort をしてるので
別に問題ないかなと思ってます。
参考