JavaScriptで数値フォーマットする標準API「Intl.NumberFormat」 (カンマ区切り、円・ドル表記、漢数字など)

ほぼすべてのブラウザやNode.jsでサポートされている数値をフォーマットするAPI「Intl.NumberFormat」を紹介する記事です。

JavaScriptで数値をカンマ区切りにしたいときにGoogleで検索してみると、正規表現を使っていたり、ループで回して3桁ごとにカンマ付ける実装を紹介する記事を多く見つけました。
しかし、それらは古い記事ということもあり、2018年現在は数値のフォーマットを実装する必要はありません。EcmaScriptで仕様策定されておりほとんどのブラウザやNode.jsで使える関数があるので紹介します。
今回紹介するコードの実行結果はすべてChromeでの結果になります。

TL;DR

Intl

i18nやl10nといった国際化対応するためのAPIです。
詳しくは「Intl - JavaScript|MDN」をお読みください。
EcmaScriptの仕様については「ここ」を読んで下さい。

Intl.NumberFormat

通過や文字など国や地域によって数の表記は違います。このAPIはその国ごとの表記を指定した表記に変換してくれるAPIを提供してくれるオブジェクトです。
詳しくはMDNの記事をお読み下さい。日本語の記事は情報が古いので英語版を参考にしてください。

以下のようにlocaleをコンストラクタの引数に指定することができます。
引数の指定が無い場合は'us-EN'が設定されます。

const formatter = new Intl.NumberFormat('ja-JP');

Intl.NumberFormat.prototype.format

数値を変換する関数です。Intl.NumberFormatのメソッドです。
IEを含むほぼすべてのブラウザで使用可能です。
よく使われそうな例を紹介します。

カンマ区切り

冒頭で説明したカンマ区切りです。3桁ごとに区切って表示する場合に使うことができます。
以下は'ja-JP'を指定していますが、'us-EN'や引数なしでも同じように3桁でカンマ区切りします。

const formatter = new Intl.NumberFormat('ja-JP');
formatter.format(1000);
// => "1,000"

通貨

数値をサクッと円やドル表記したいことはあると思います。
円の表記は以下のようにNumberFormatの第2引数にオブジェクトを渡すことで実現可能です。
第2引数のオプションについてもやはりMDNの「Intl.NumberFormat」に詳しく載っていますので興味ある方はそちらをお読み下さい。

const formatter = new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY'
});
formatter.format(1000);
// => "¥1,000"

もちろん、ドルやユーロなども対応しています。

let formatter = new Intl.NumberFormat('us-EN', {
  style: 'currency',
  currency: 'USD'
});
formatter.format(1000);
// => "$1,000.00"

let formatter = new Intl.NumberFormat('de-DE', {
  style: 'currency',
  currency: 'EUR'
});
formatter.format(1000)
// => "1.000,00 €"

漢数字

数値を漢数字の文字列に変換することも可能です。
以下は「中国で使用される簡体字で書かれる中国語の10進数の漢数字」という指定をしています。
zh-Hans-CNまでが「中国で使用される簡体字で書かれる中国語」を指し、u-nu-hanidecが「10進数の漢数字」を指します。

const formatter = new Intl.NumberFormat('zh-Hans-CN-u-nu-hanidec');
formatter.format(1234567890);
// => "一,二三四,五六七,八九〇"

Intl.NumberFormat.prototype.formatToParts

上記のようにformat関数で数値のフォーマットが行えますが、新しいAPIであるformatToPartsに関しても紹介しておきます。

執筆時点(2018/04/15)ではChrome63とFirefox58で使えるようになっています。
Node.jsも次期バージョンのv10では使えます。
EcmaScriptの仕様は「ここ」にあります。

数値のカスタムフォーマットを行うことが可能になります。
formatToPartsの戻り値は{type: string, value: string}のオブジェクトの配列です。

const formatter = new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY'
});
formatter.formatToParts(1000);
// => [ { type: 'currency', value: '¥' },
//      { type: 'integer', value: '1' },
//      { type: 'group', value: ',' },
//      { type: 'integer', value: '000' } ]

オブジェクトの配列なので、あとは好き勝手いじることが可能です。
以下はMDNに掲載されている例をJPYにしてみた例です。

const num = 1000;
const formatter = new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY'
});
const yen = formatter.formatToParts(num).map(({type, value}) => {
  switch (type) {
    case 'currency': return "<strong>" + value + "</strong>";
    default: return value;
  }
}).reduce((string, part) => {return string + part});
console.log(yen);
// => "<strong>¥</strong>1,000"

最後に

数値のフォーマット関数は標準で用意されているAPIを使いましょう。

補足(2018/04/17)

はてブでSafariで使えないというコメントがあったので補足します。
Intl.NumberFormat.prototype.formatはSafari10から対応しています。
Intl.NumberFormat.prototype.formatToPartsは使えません。
MDNの日本語版のブラウザ対応表が更新されていませんでした。英語版では10から対応と記載がありました。Safari11.1でも確認済みです。
また、MDNのIntl.NumberFormat.prototype.formatの日本語版のSafariのサポートバージョンも更新しておきました。

参考

最後までお読みいただきありがとうございました。不備や質問がございましたらコメント欄に記載またはTwitterで @shisama_ 宛にメンション飛ばして下さい。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.