以前ゼロパディングで桁数を合わせる方法のメモを書いていましたが、三桁ごとにカンマ区切りのフォーマットもよくやるよな〜と思ったのでやり方のメモ。
こんなの
1234567890 => "1,234,567,890" 1234567890.1235 => "1,234,567,890.1235" -1234567 => "-1,234,567" -1234567.89054321 => "-1,234,567.89054321"
結論 Number.toLocaleString
か Intl.NumberFormat
を使うのが簡単
※ 但し小数点以下の有効桁数に注意
Number.toLocaleString を使う
Number.prototype.toLocaleString()
numObj.toLocaleString([locales [, options]])
新しいlocales
とoptions
引数で アプリケーションは フォーマット変換で使われる言語を指定でき、関数の振る舞いをカスタマイズできます。古い実装では、locales
とoptions
引数は無視され、使われるロケールや返される文字列の形式は完全に実装依存です。
cf. Number.prototype.toLocaleString() - JavaScript | MDN
引数を指定しないとフォーマットはロケール依存になり、小数点以下は特定桁数で四捨五入される
const numbers = [1234567890, 1234567890.1235, -1234567, -1234567.89054321]; const numberFormat = (num: number): string => { return num.toLocaleString(); }; numbers.map((num) => numberFormat(num)); // => '1,234,567,890' // => '1,234,567,890.124' // => '-1,234,567' // => '-1,234,567.891'
maximumFractionDigits
オプションを使い小数点以下の桁数を保持する (※但し最大 20桁)
const numbers = [1234567890, 1234567890.1235, -1234567, -1234567.89054321]; const numberFormat = ( num: number, options?: Intl.NumberFormatOptions ): string => { return num.toLocaleString(undefined, options); }; numbers.map((num) => numberFormat(num, {maximumFractionDigits: 20})); // => '1,234,567,890' // => '1,234,567,890.1235' // => '-1,234,567' // => '-1,234,567.89054321'
₍ ᐢ. ̫ .ᐢ ₎👌
Intl.NumberFormat を使う
Intl.NumberFormat
new Intl.NumberFormat([locales [, options]]).format(number)
ローケルを指定しない基本的な使い方では、既定のローケルとオプションで書式化された文字列が返されます。
cf. Intl.NumberFormat - JavaScript | MDN
locales
, options
は toLocaleString
と同じ
引数を指定しないとフォーマットはロケール依存になり、小数点以下は特定桁数で四捨五入される
const numbers = [1234567890, 1234567890.1235, -1234567, -1234567.89054321]; const numberFormat = (num: number): string => { return new Intl.NumberFormat().format(num); }; numbers.map((num) => numberFormat(num)); // => '1,234,567,890' // => '1,234,567,890.124' // => '-1,234,567', // => -1,234,567.891'
maximumFractionDigits
オプションを使い小数点以下の桁数を保持する (※但し最大 20桁)
const numbers = [1234567890, 1234567890.1235, -1234567, -1234567.89054321]; const numberFormat = (options?: Intl.NumberFormatOptions) => (locales?: string | string[]) => (num: number): string => { return new Intl.NumberFormat(locales, options).format(num); }; // 小数点以下 20 桁まで有効にするフォーマット const format = numberFormat({ maximumFractionDigits: 20 }); const formatJP = numberFormat('ja-JP') numbers.map((num) => formatJP(num)); // => '1,234,567,890', // => '1,234,567,890.1235', // => '-1,234,567', // => '-1,234,567.89054321' const formatDE = numberFormat('de-DE') numbers.map((num) => formatDE(num)); // => 1.234.567.890', // => '1.234.567.890,1235', // => '-1.234.567', // => '-1.234.567,89054321' const formatFI = numberFormat('fi-FI') numbers.map((num) => formatFI(num)); // => '1 234 567 890', // => '1 234 567 890,1235', // => '−1 234 567', // => '−1 234 567,89054321'
₍ ᐢ. ̫ .ᐢ ₎👌
toLocaleString
, Intl.NumberFormat
の桁数のオプション
minimumIntegerDigits
… 整数の最小桁数。可能な値は1から21, デフォルトは1
minimumFractionDigits
... 小数桁の最小数。可能な値は0から20, 数値フォーマットのデフォルトは0
maximumFractionDigits
… 小数桁の最大数。可能な値は0から20, 数値フォーマットのデフォルトは、minimumFractionDigits
と3
の大きい方minimumSignificantDigits
… 有効桁の最小数。可能な値は1から21, デフォルトは1
maximumSignificantDigits
… 有効桁の最大数。可能な値は1から21, デフォルトは21
cf. Intl.NumberFormat() constructor - JavaScript | MDN
あまり用途はなさそうだけど、小数点以下が 20 桁以上でそれを保持したい場合は整数部と小数点以下に分離して、整数部分をフォーマットした後に小数点以下と文字列結合する必要がある
const format = (num: number): string => { const numStrs = String(num).split('.'); return [ Number(numStrs[0]).toLocaleString(), numStrs.slice(1).join(''), ].filter(Boolean).join('.'); }; format(111111.098765432109876543210987); // => "111,111.098765432109876543210987" format(-111111.098765432109876543210987); // => "-111,111.098765432109876543210987"
数字のフォーマットを自前で実装するパターン
文字列にして自前でフォーマットしてしまうなら小数点以下が丸められるトラップにははまらない。
ただ、そんなケースはあまり無さそうなので自前実装するメリットほぼ無さそうだけどスクリプト書いてみたので載せておきます。
再帰関数で ,
区切りにする
整数部分を再帰関数で ,
区切りにして、小数点以下と文字列結合する
const separate = (numStr: string, separator: string = ','): string => { const length = numStr.length; if (length > 3) { const splitIndex = length - 3; // 後ろから 3文字づつ確定していく return [ separate(numStr.substring(0, splitIndex), separator), numStr.substring(splitIndex), ].filter(Boolean).join(separator); } return numStr; }; type FormatOption = { separator?: string; decimalPoint?: string; }; const formatNumber = ( num: number, options?: FormatOption, ): string => { const numStrs = String(num).split('.'); return [separate(numStrs[0], options?.separator), numStrs.slice(1).join('')] .filter(Boolean) .join(options?.decimalPoint || '.'); }; const numbers = [1234567890, 1234567890.1235, -1234567, -1234567.89054321]; numbers.map((num) => formatNumber(num)); // => '1 234 567 890', // => '1 234 567 890.1235', // => '-1 234 567', // => '-1 234 567.89054321'
₍ ᐢ. ̫ .ᐢ ₎👌
正規表現を使うパターン
正規表現は自信が無いのでググって出てきた replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,')
を使います。
この正規表現も整数部分でしか上手く動作しないので、整数部分を正規表現で ,
区切りにしてから小数点以下と結合します
type FormatOption = { separator?: string; decimalPoint?: string; }; const formatNumber = ( num: number, options?: FormatOption, ): string => { const numStrs = String(num).split('.'); return [ numStrs[0].replace( /(\d)(?=(\d\d\d)+(?!\d))/g, `$1${options?.separator || ','}` ), numStrs.slice(1).join(''), ] .filter(Boolean) .join(options?.decimalPoint || '.'); }; const numbers = [1234567890, 1234567890.1235, -1234567, -1234567.89054321]; numbers.map((num) => formatNumber(num, { separator: '.', decimalPoint: ',' })); // => '1.234.567.890', // => '1.234.567.890,1235', // => '-1.234.567', // => '-1.234.567,89054321'
₍ ᐢ. ̫ .ᐢ ₎👌
所管
Intl.NumberFormat
は今回のメモを書くにあたって調べていて初めて知りました。
オプションで locale に合ったフォーマットができるので Number.toLocaleString
か Intl.NumberFormat
を使えば良さそう。
ただし、デフォルトでは小数点以下が丸められるので丸めたくない時は maximumFractionDigits
オプションを使う必要がある。
ただこの2つの方法オプションも似ているので同じようなものが 2 つ存在していてどちらの方が良いチョット解ってない。2021年7月7日現在では toLocaleString
は現行の標準になっているのでこっちを使うでいいのかな?
,
これ コンマなのカンマなの???????
[参考]
- Number.prototype.toLocaleString() - JavaScript | MDN
- Intl.NumberFormat - JavaScript | MDN
- JavaScriptで数値を3桁のカンマ区切りにする方法! | Qumeruマガジン
- 数値をカンマ区切りにする - Qiita
- JavaScriptで小数点以下の部分を取得する3つの方法 | PisukeCode - Web開発まとめ
夏樹みくる ちゃんハピバ 🎉🎂