数値を3桁区切りにするには
1234567 を 1,234,567 のように 3 桁ごとのカンマで区切った文字列にする基本形を各言語で示す。
区切り文字がロケールで変わる点と、標準の書式指定が無い言語での書き方、小数や大きな整数を渡したときの注意までを扱う。
公開:
各言語見出しの横のバッジは検証状態を表す。実行確認済みはコードを実際に実行して確認したもの、静的確認は構文と公式 API ドキュメントで確認したものである。
Python 実行確認済み
n = 1234567
print(f"{n:,}") # 1,234,567
print(f"{-9876543:,}") # -9,876,543
print(f"{1234567.891:,.2f}") # 1,234,567.89
print(format(n, "_")) # 1_234_567
# 文章に埋め込むときも f-string の中で書式を指定する
# ("合計: " + total + "円" のように + でつなぐと TypeError になる)
total = 1980000
print(f"合計: {total:,}円") # 合計: 1,980,000円書式指定に , を付けると 3 桁ごとにカンマが入り、,.2f のように小数の桁数とも組み合わせられる。
この書き方はロケールに左右されず常にカンマを使う一方、ロケールに従う n 指定は locale.setlocale を呼ばない限り区切りを入れず、format(1234567, "n") は 1234567 のままになる。
文章に埋め込むときに + で数値をつなぐと TypeError になるため、f-string の中で書式を指定する。
うまくいかない時: Python で「TypeError: can only concatenate str (not "int") to str」が直らない
JavaScript 実行確認済み
const n = 1234567.891;
console.log(n.toLocaleString("en-US")); // 1,234,567.891
console.log(n.toLocaleString("de-DE")); // 1.234.567,891
console.log(n.toLocaleString("ja-JP", { maximumFractionDigits: 0 })); // 1,234,568
// 何度も書式化するなら Intl.NumberFormat を作って使い回す
const yen = new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY" });
console.log(yen.format(1980000)); // ¥1,980,000
// 正規表現で区切る書き方は、小数部の 4 桁以上まで区切ってしまう
console.log(String(1234.5678).replace(/\B(?=(\d{3})+(?!\d))/g, ",")); // 1,234.5,678toLocaleString と Intl.NumberFormat は、渡したロケールの規則で区切り文字と小数点を決める。
ロケールを省略すると実行環境の設定に従い、サーバーとブラウザで表示が変わることがあるので明示する。
小数部は既定で 3 桁までに丸められ、桁数は maximumFractionDigits で変えられる。
正規表現で区切る書き方は整数部と小数部を区別しないため、小数部が 4 桁以上あると 1,234.5,678 のように壊れる。
TypeScript 実行確認済み
// 書式は Intl.NumberFormat に任せ、インスタンスは 1 つ作って使い回す
const formatter: Intl.NumberFormat = new Intl.NumberFormat("ja-JP");
function withCommas(value: number | bigint): string {
return formatter.format(value);
}
console.log(withCommas(1234567)); // 1,234,567
console.log(withCommas(-9876543.21)); // -9,876,543.21
console.log(withCommas(0.1234567)); // 0.123(小数は既定で 3 桁まで)
// Number.MAX_SAFE_INTEGER を超える整数は bigint で渡さないと下の桁が崩れる
console.log(withCommas(12345678901234567890)); // 12,345,678,901,234,567,000
console.log(withCommas(12345678901234567890n)); // 12,345,678,901,234,567,890toLocaleString は呼び出すたびにロケールのデータを探し直すので、何度も書式化するなら Intl.NumberFormat を 1 つ作って使い回す。
format は number と bigint のどちらも受け取るが、Number.MAX_SAFE_INTEGER を超える整数は number にした時点で下の桁が崩れるため、bigint のまま渡す。
tsconfig の target が ES2020 より古い設定では、bigint を渡した行が TS2345 になり、12345678901234567890n のようなリテラルも書けない。
うまくいかない時: TypeScript で「Argument of type ... is not assignable」が解消できない
Go 実行確認済み
package main
import (
"fmt"
"math"
"strconv"
)
// 標準ライブラリに 3 桁区切りの書式は無いので、文字列にしてから区切る
func withCommas(n int64) string {
s := strconv.FormatInt(n, 10)
sign := ""
if s[0] == '-' {
sign, s = "-", s[1:]
}
for i := len(s) - 3; i > 0; i -= 3 {
s = s[:i] + "," + s[i:]
}
return sign + s
}
func main() {
fmt.Println(withCommas(1234567)) // 1,234,567
fmt.Println(withCommas(-9876543)) // -9,876,543
fmt.Println(withCommas(999)) // 999
fmt.Println(withCommas(math.MinInt64)) // -9,223,372,036,854,775,808
}fmt の書式指定には 3 桁区切りが無いため、strconv.FormatInt で文字列にしてから後ろから 3 桁ごとにカンマを差し込む。
符号を付けたまま区切ると -123456 が -,123,456 になるので、負の数は符号を外してから区切る。
ロケールに合わせて区切りたいときは golang.org/x/text/message の Printer を使うと、language.Japanese なら 1,234,567、language.German なら 1.234.567 と書式化できる。
Rust 実行確認済み
// 標準ライブラリに 3 桁区切りの書式は無いので、数字の列に , を差し込む
fn with_commas(n: i64) -> String {
let digits = n.unsigned_abs().to_string();
let mut out = String::new();
for (i, c) in digits.chars().enumerate() {
if i > 0 && (digits.len() - i) % 3 == 0 {
out.push(',');
}
out.push(c);
}
if n < 0 { format!("-{}", out) } else { out }
}
fn main() {
println!("{}", with_commas(1234567)); // 1,234,567
println!("{}", with_commas(-9876543)); // -9,876,543
println!("{}", with_commas(999)); // 999
println!("{}", with_commas(i64::MIN)); // -9,223,372,036,854,775,808
}標準ライブラリの書式指定には 3 桁区切りが無いので、数字の列を先頭から見て、残りの桁数が 3 の倍数になる位置にカンマを入れる。
符号は unsigned_abs で外してから最後に付け直す。
abs を使わないのは、i64::MIN の絶対値が i64 に収まらず、abs ではオーバーフローでパニックするためである。
Java 実行確認済み
import java.text.NumberFormat;
import java.util.Locale;
public class FormatNumber {
public static void main(String[] args) {
System.out.println(String.format(Locale.US, "%,d", 1234567)); // 1,234,567
System.out.println(String.format(Locale.US, "%,.2f", 1234567.891)); // 1,234,567.89
// 区切り文字はロケールで変わる
System.out.println(String.format(Locale.GERMANY, "%,d", 1234567)); // 1.234.567
// NumberFormat は小数部を既定で 3 桁まで出す
NumberFormat nf = NumberFormat.getInstance(Locale.JAPAN);
System.out.println(nf.format(1234567.891)); // 1,234,567.891
System.out.println(nf.format(-9876543)); // -9,876,543
}
}String.format の %,d と %,.2f は、渡したロケールの区切り文字で 3 桁ごとに区切る。
ロケールを省略すると実行環境の既定ロケールが使われ、ドイツ語の環境では 1.234.567 になるので、出力先に合わせて明示する。
NumberFormat.getInstance が返す書式は小数部を既定で 3 桁まで出し、桁数は setMaximumFractionDigits で変えられる。
C# 実行確認済み
using System.Globalization;
int n = 1234567;
Console.WriteLine(n.ToString("N0", CultureInfo.InvariantCulture)); // 1,234,567
Console.WriteLine(1234567.891.ToString("N2", CultureInfo.InvariantCulture)); // 1,234,567.89
Console.WriteLine(n.ToString("#,0", CultureInfo.InvariantCulture)); // 1,234,567
// 区切り文字はカルチャで変わる
Console.WriteLine(n.ToString("N0", new CultureInfo("de-DE"))); // 1.234.567
// 文字列補間でもカルチャを明示できる(.NET 6 以降)
int total = 1980000;
Console.WriteLine(string.Create(CultureInfo.InvariantCulture, $"合計: {total:N0}円")); // 合計: 1,980,000円書式指定子 N0 は小数部なしの 3 桁区切りで、N2 なら小数第 2 位まで出し、カスタム書式 #,0 でも同じ区切りになる。
どれもカルチャの区切り文字を使うため、カルチャを省略すると実行環境の設定に従い、de-DE では 1.234.567 になる。
文字列補間で書式化するときは、string.Create に CultureInfo を渡すとカルチャを固定できる。
つまずき
区切り文字は言語ではなくロケールで決まる。
英語圏や日本では 1,234,567 だが、ドイツ語では 1.234.567 になり、フランス語では狭い改行なしスペース(U+202F)で区切る(Node.js 22 と Java 21 で確認)。
インドの英語(en-IN)では 12,34,567 のように、下の 3 桁より上を 2 桁ごとに区切る。
ロケールを省略した書き方は実行する環境の設定に従うため、開発機では 1,234,567 と出ていた表示が、サーバーでは別の形になることがある。
表示先の読者が決まっているなら、ロケールを明示して固定する。
標準の書式が無い言語では自前で区切る
Python・JavaScript・TypeScript・Java・C# は標準の書式指定だけで 3 桁区切りにできるが、Go と Rust の標準ライブラリにはその書式が無い。
自前で区切る関数を書くときは、負の数、999 以下の桁数の少ない値、型の最小値の 3 つを試しておくと、カンマの位置のずれや絶対値のオーバーフローに気付ける。
区切った文字列は数値に戻しにくい
3 桁区切りは表示のための書式であり、区切った文字列はそのままでは数値に戻せないことが多い。
Python の int("1,234,567") は ValueError になり、JavaScript の Number("1,234,567") は NaN、parseInt("1,234,567", 10) は最初のカンマで読むのをやめて 1 を返す。
保存や受け渡しには区切らない数値を使い、区切りは画面に出す直前に付ける。