数字を桁区切りにする

大きな数字を読みやすくするために区切って表示するにはどうしたらいいか?

それはチュートリアルにちゃんと書いてある

基本的にはこうか、

# Python 3.0
import locale
n = 1234567890
locale.setlocale(locale.LC_ALL, "")
s = locale.format("%d", n, grouping=True)
print(s)  # 結果: 1,234,567,890

数字を区切る場所は地域や言語によって異なる*1。localeを使うとそれらの違いに対応してくれるはずなのだが、なぜか日本語のロケールにしても3桁区切りになっている。日本語は万億兆京垓……なので、本来なら4桁ごとに区切らないといけない。

昔、自分が使っていた電卓はアポストロフィーで4桁ごとに区切るようになっていたが、それと同じようにするにはどうしたらいいか? 自分で新しいロケールが作れるといいのだが簡単な方法が見つからなかった。しょうがないのでデバッグ用変数でも使いますか:

import locale
##locale.setlocale(locale.LC_ALL, "")  # してもしなくてもいい

# 現在のロケールに関する値を上書きするための辞書。
# この値は resetlocale でもクリアされないので注意。
locale._override_localeconv.update(grouping=[4, 0], thousands_sep="'")

n = 12345567890
s = locale.format("%d", n, grouping=True)
print(s)  # 結果: 123'4556'7890

ロケール値を上書きしてしまうくらいなら、初めから自分で実装した方がいいかもしれない:

def splitper(s, n):
    assert n > 0
    d, m = divmod(len(s), n)
    if m:
        yield s[:m]
    for i in range(d):
        a = i * n + m
        yield s[a:a+n]

print(*splitper("1234568790", 4), sep="'")  # 結果: 12'3456'8790


ちなみに、localeはいろいろな地域のいろいろな表記に対応するため、かなり柔軟にできているようで*2、たとえばこんなこともできる:

import locale
locale.setlocale(locale.LC_ALL, "")

# 最初は1桁、次は2桁、残りは3桁づつ
locale._override_localeconv['grouping'] = [1, 2, 3, 0]
print(locale.format("%d", 1234567890, grouping=True))  # 結果: 1,234,567,89,0

# 最初は2桁、次は1桁、残りは区切らない
locale._override_localeconv['grouping'] = [2, 1, locale.CHAR_MAX]
print(locale.format("%d", 1234567890, grouping=True))  # 結果: 1234567,8,90

オゥワー、ほんと i18n は地獄だNEー

*1:信じられないことに小数点や数字の区切りに使う文字すら異なる場合がある。

*2:詳しくはlocaleconvのドキュメントを参照。