いそべやきはビールの夢をみる

今日もしがないえんじにあ

【正規表現】数値を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)を参照しています。その上でカンマを付与しています。

 

複雑なことしてるようですが、数字一つ一つについて正規表現適用して、マッチしたらカンマ付きの文字に変えて・・・ということを繰り返してるってことですね。

 

一発で変換できるメソッドがあればなあ〜ドラえも〜んという気分です。