【Rubyプログラミング問題】値札分割メソッド(split_price)を作成してください：解答編


##はじめに

先日、こんなQiita記事（というかプログラミング問題）を書きました。

[【Rubyプログラミング問題】値札分割メソッド(split_price)を作成してください - Qiita](http://qiita.com/jnchito/items/2db66f9a5c7d55aed925)

解答をコメントしてくださったみなさん、どうもありがとうございました。
今回は僕の作った解答と、いただいた解答の中から僕が一番イケてると思ったコードを紹介したいと思います。

## おさらい：出題したのはこんな問題でした

ユーザーが自由に入力できる値札データがある。
このデータ（文字列）を以下のようなルールで分割するメソッド、 `split_price` を作成せよ。

```ruby 
'110.0万円'     => ['110.0', '万円']
'2015円'        => ['2015', '円']
'1,123,456円'   => ['1,123,456', '円']
'110 - 120万円' => ['110 - 120', '万円']
'２０１５円'    => ['２０１５', '円']
'価格未定'      => ['価格未定', '']
nil             => ['', '']
```


##僕の作った解答

僕が作った解答はこちらです。

```ruby
def split_price(price_text)
  regex = /([^万円]+)(万?円)/
  regex.match(price_text).to_a[1..2] || [price_text.to_s, '']
end
```

### 簡単な解説

`regex = /([^万円]+)(万?円)/` で正規表現オブジェクトを作ります。
この正規表現の意味は以下の二つのパートから成り立っています。

- 「万」でも「円」でもない文字が1つ以上続く文字列（`[^万円]+`）
- 「円」または「万円」（`万?円`）

このパートはそれぞれ `( )` で囲まれているので、`match`を実行するとキャプチャされます。（パターンに一致した場合）

具体的にはこんな結果になります。

```ruby
regex = /([^万円]+)(万?円)/
# => /([^万円]+)(万?円)/
regex.match('110.0万円')
# => #<MatchData "110.0万円" 1:"110.0" 2:"万円">
regex.match('2015円')
# => #<MatchData "2015円" 1:"2015" 2:"円">
regex.match('価格未定')
# => nil
regex.match(nil)
# => nil
```

`match`の実行結果は`MatchData`です。
これを`to_a`で配列化すると、マッチした文字列全体とキャプチャされた文字列が配列で返ってきます。
また、`nil.to_a` は空の配列（`[]`）になります。

```ruby
regex.match('110.0万円').to_a 
# => ["110.0万円", "110.0", "万円"]
regex.match('2015円').to_a 
# => ["2015円", "2015", "円"]
regex.match('価格未定').to_a
# => []
regex.match(nil).to_a
# => []
```

マッチした文字列に対しては返ってきた配列の後ろ2件を返せばOKです。
なので、`[1..2]`で配列の2番目から3番目までを取得しています。

一方、空の配列に対して`[1..2]`を呼ぶと`nil`が返ります。
`nil`は偽として扱われるため、`||`（OR条件）でつないで後ろに続くコードを実行します。
よって`price_text`が`"価格未定"`や`nil`だったりした場合は `[price_text.to_s, '']`が呼ばれ、`['価格未定', '']`や`['', '']`が返ります。

解説は以上です。
言葉だとわかりにくい部分も多いと思うので、irbやPryを使って自分の手で動かしてみると良いかもしれません。

## 優秀賞の発表

さて、僕は上記のような模範解答を用意していたのですが、この問題を公開してみると僕よりもスマートな解答を作ってくれた方がたくさんいました（汗）。
僕もまだまだですね。もっと精進します。

中でも僕が一番「おおっ」と思ったのは @284km さんのこちらのコードです。

```ruby
def split_price(price_text)
  price_text.to_s.match(/([^万円]*)(.*)/)[1..2]
end
```

僕の解答例と基本的なロジックは似ていますが、正規表現を工夫してどんな文字列でもマッチするようになっているため、よりシンプルな実装になっています。

```ruby
'110.0万円'.to_s.match(/([^万円]*)(.*)/) 
# => #<MatchData "110.0万円" 1:"110.0" 2:"万円">
'2015円'.to_s.match(/([^万円]*)(.*)/) 
# => #<MatchData "2015円" 1:"2015" 2:"円">
'価格未定'.to_s.match(/([^万円]*)(.*)/) 
# => #<MatchData "価格未定" 1:"価格未定" 2:"">
nil.to_s.match(/([^万円]*)(.*)/) 
# => #<MatchData "" 1:"" 2:"">
```

`match`の結果が`nil`にならないので、`||`でつなぐような処理がいらなくなります。いやあ、素晴らしいです！

## まとめ
というわけで、この記事では「値札分割メソッド」の解答例と優秀賞を紹介しました。
実装をシンプルにするためのポイントはやはり正規表現ですね。
正規表現をうまく活用できている人ほど、コードがシンプルになっていると思います。

「正規表現ってよく聞くけどさっぱりわかんないんです (><)」という方はオライリーの「詳説正規表現」をオススメします。
正規表現を全く知らない人でもよくわかるように手取り足取り教えてくれます。


<a href="http://www.amazon.co.jp/gp/product/4873113598/ref=as_li_ss_tl?ie=UTF8&camp=247&creative=7399&creativeASIN=4873113598&linkCode=as2&tag=junic05-22">詳説 正規表現 第3版</a>

![download.jpg](https://qiita-image-store.s3.amazonaws.com/0/7465/6f6afb63-07dc-f2bf-b353-63cf0370e110.jpeg "download.jpg")

みなさんも正規表現やRubyの便利な標準ライブラリを活用して、スマートなコードを書けるようになりましょう！


### あわせて読みたい

他の方の解答は元記事のコメント欄にいろいろと載っています。
こちらも参考にしてみてください。


[【Rubyプログラミング問題】値札分割メソッド(split_price)を作成してください - Qiita](http://qiita.com/jnchito/items/2db66f9a5c7d55aed925)