Paizaの問題「大きな数の3桁区切り」で試行錯誤!
最初は正規表現で頑張ったけど、実は toLocaleString() の方がスマートだった!?
技術メモとしてまとめておくよ。
問題の概要
入力: 超デカい整数
出力: 3桁ごとにカンマを挿入した文字列
※位の小さい方から 3 けたごとにカンマ区切りで出力
※Nの桁数は 3 の倍数とは限らない
例:
入力: 12345678901234567890
出力: 12,345,678,901,234,567,890
解法①: 正規表現 + replace()
console.log(input.replace(/\B(?=(\d{3})+(?!\d))/g, ","));
解説
\B
→ 先頭を除く位置にマッチ(\b の逆)
(?=(\d{3})+(?!\d))
→ 3桁ごとの数字のグループが一回以上繰り返されている、次が数字じゃない(=3桁数字グループの間)位置にマッチ。
.replace(..., ",")
でカンマを挿入
メリット: 柔軟にカスタム可能
デメリット: 正規表現ミスるとバグりやすい(僕も最初、先頭にカンマ入る事故発生💀)
解法②: toLocaleString()
console.log(BigInt(input).toLocaleString());
解説
toLocaleString()
→ ロケール対応 で数値をフォーマット
BigInt
必須 →(Number
型では処理できない大きな数を扱いたい場合、BigInt
を使う必要がある)
メリット: 簡潔 & 国際対応OK
デメリット: カスタマイズ性低め
まとめ
汎用性なら正規表現
お手軽 & 国際対応なら toLocaleString()
おまけ
const rl = require('readline').createInterface({input: process.stdin});
rl.on('line',(input) => {
function addCommas(num) {
// 数字を文字列にしてから逆順にし、処理後に逆転させる
let str = num.toString().split('').reverse().join('');
let result = [];
for (let i = 0; i < str.length; i++) {
if (i > 0 && i % 3 === 0) {
result.push(','); // 3桁ごとにカンマを追加
}
result.push(str[i]); // 現在の数字を追加
}
// 最後に文字列を逆順にして元に戻す
return result.reverse().join('');
}
console.log(addCommas(input));
rl.close();
});