【正規表現】数値を3桁区切りにしてカンマを付与したい
345678みたいなただの数字の羅列を、345,678みたいにしたい。調べたら沢山解説記事がありました。
345678.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\1,')
え?は?全然わからないぞ。
とりあえず分解して見てみよう。
①gsubメソッド使ってるな・・・
文字列 .gsub( / pattern / , ' replacement ' ) で文字列の中で、指定した正規表現(pattern)に一致した文字をreplacementに置き換えることができる。
②345678.to_sってなんだ・・・
to_sで数字を文字列にしている。なんのためかといえば①で書いたgsubメソッドは文字列にしか使えないから。
345678という数字を文字列にして、gsubメソッドでカンマを付与した形に置き換えているのか。大まかな骨組みは理解。
③正規表現
/(\d)(?=(\d{3})+(?!\d))/
難所ですが、?=(肯定的先読み)と?!(否定的先読み)の使い方が分かれば意外と簡単。
A(?=B) 直後にBがあるAに一致
A(?!B) 直後にBがないAに一致
ややこしい・・・実際に当てはめてみる。(\d)(?=(\d{3})+(?!\d))を見やすくスペース開けて見ます。
(\d) (?=(\d{3})+(?!\d))
A(?=B) の形になるので、「直後に(\d{3})+(?!\d)がある(\d)に一致」と読める。
(\d{3})+(?!\d)を詳しく。
(\d{3})は数字が3つ連続している状態。+は直前の文字の繰り返し。(?!\d)は直後に数字がない状態。つまり、数字が3の倍数だけ続いている状態を示している。
まとめると、/(\d)(?=(\d{3})+(?!\d))/ は
「直後に数字が3の倍数だけ続いている数字」というpatternです。
④置換でカンマの付与
'\1,' ってなんだ、いきなり数字出てきた・・・
\1とか\2で後方参照ができるそうです。通常は/pattern /というように正規表現を書きますが、/(pattern) / と()で囲むことで、その文字を参照できるようになるらしい。
\1 一つ目の()の中身を参照
\2 一つ目の()の中身を参照
ここでは、1つ目の()つまり/(\d)(?=(\d{3})+(?!\d))/ の(\d)を参照しています。その上でカンマを付与しています。
複雑なことしてるようですが、数字一つ一つについて正規表現適用して、マッチしたらカンマ付きの文字に変えて・・・ということを繰り返してるってことですね。
一発で変換できるメソッドがあればなあ〜ドラえも〜んという気分です。