Go 言語(以下 Golang)で
int(1000)
--->"1,000"
とコンマ区切りでフォーマット出力したい。しかし、
fmt
パッケージには専用の関数がなさげ。どうしよう。
独自実装やサードパーティのパッケージを使わずに、golang.org 管轄下のパッケージでフォーマットできないものか。
「golang コンマ区切り カンマ区切り 出力 フォーマット」でググるも、独自実装だったり、コンマ区切りの入力を処理するものばかりだったので自分のググラビリティとして。
TL; DR (今北産業)
-
Go の準標準モジュール
golang.org/x/text
の message パッケージで可能。-
message
は、ロケールに合わせたテキスト整形ツール郡でfmt
の代替パッケージです。
-
-
桁の区切りカンマやピリオドは国によって記法が異なる。
message
で調整が可能。 -
マスター、動くものをくれ。
package main import ( "golang.org/x/text/language" "golang.org/x/text/message" ) func main() { value := 1000 p := message.NewPrinter(language.Japanese) p.Printf("%d\n", value) // Output: 1,000 }
- オンラインで動作をみる @ Go playground
ロケールによる表記の違いpackage main import ( "golang.org/x/text/language" "golang.org/x/text/message" "golang.org/x/text/number" ) func main() { value := 1234567.89 for _, langTag := range []language.Tag{ language.English, language.Japanese, language.French, } { p := message.NewPrinter(langTag) p.Println(langTag) p.Printf(" Message: %f\n", value) p.Printf(" Number : %v\n", number.Decimal(value)) } // Output: // en // Message: 1,234,567.890000 // Number : 1,234,567.89 // ja // Message: 1,234,567.890000 // Number : 1,234,567.89 // fr // Message: 1 234 567,890000 // Number : 1 234 567,89 }
- オンラインで動作をみる @ Go playground
TS; DR
1000桁区切りにコンマは国によって異なる
小数点や桁の区切りは、国によって記法が異なることをご存じでしょうか。
例えば、日本では 1234567.89
という値は 1,234,567.89
とも記載できますが、1.234.567,89
だったり 12,34,567.89
、1 234 567,89
や 1'234'567,89
という、日本とは異なる記法の国もあるのです。
日本でも「百二十三万四千五百六十七点八九」という記法もある事を考えればわかる気もします。
他にも、日付の 2001 年 10 月 11 日を 01/10/11
という YMD
記法の国もあれは、11/10/01
(DMY
)だったり 10/11/01
(MDY
)という国もあります。
つまり、国によって数値の記法が異なるということです。
表記のローカライズ
そこで、「その国に合わせた記述方法」に変換することを「ローカライズ」(地域化)と言います。
OS で「ロケール」を変更すると、数値や日付の表記が変わるのを経験したことはないでしょうか。アレです。
ゆうて、筆者も「なぜ標準で数値のフォーマッターがないんだ。PHP なら number_format
があるのに」と思い調べていたところ、number モジュールがフォーマッターであることはわかったものの、message
の Printer
オブジェクトを通して処理しています。
なぜそんな七面倒臭いことをするのだろうと思って message のドキュメントを読んでいたら「ロケールの問題か!」と気付かされたのです。
message から以下の抜粋を翻訳してみました。
Localized Formatting
A format string can be localized by replacing any of the print functions of fmt with an equivalent call to a Printer.
p := message.NewPrinter(message.MatchLanguage("en")) p.Println(123456.78) // Prints 123,456.78 p.Printf("%d ducks in a row", 4331) // Prints 4,331 ducks in a row p := message.NewPrinter(message.MatchLanguage("nl")) p.Printf("Hoogte: %.1f meter", 1244.9) // Prints Hoogte: 1,244.9 meter p := message.NewPrinter(message.MatchLanguage("bn")) p.Println(123456.78) // Prints ১,২৩,৪৫৬.৭৮
Printer currently supports numbers and specialized types for which packages exist in x/text. Other builtin types such as time.Time and slices are planned.
Format strings largely have the same meaning as with fmt with the following notable exceptions:
- flag # always resorts to fmt for printing
- verb 'f', 'e', 'g', 'd' use localized formatting unless the '#' flag is specified.
- verb 'm' inserts a translation of a string argument.
See package fmt for more options.
(Localized Formatting | message @ pkg.go.dev より)
▼ 以下筆者翻訳
ローカライズされたフォーマットによる文字列整形
文字列のフォーマット(整形)は、
fmt
のmessage.Printer
オブジェクトのメソッドに置き換えることでローカライズ(地域化)することができます。p := message.NewPrinter(message.MatchLanguage("en")) p.Println(123456.78) // 出力: "123,456.78" p.Printf("%d ducks in a row", 4331) // 出力: "4,331 ducks in a row" p := message.NewPrinter(message.MatchLanguage("nl")) p.Printf("Hoogte: %.1f meter", 1244.9) // 出力: "Hoogte: 1,244.9 meter" p := message.NewPrinter(message.MatchLanguage("bn")) p.Println(123456.78) // 出力: "১,২৩,৪৫৬.৭৮"
現在、
message.Printer
型は、数字とx/text
パッケージに存在する特殊な型のみをサポートしています。その他のtime.Time
やスライスなどのビルトインの型は、今後実装が予定されています。文字列のフォーマットは、以下の顕著な例外を除いて、
fmt
とほぼ同じ意味を持っています
#
フラグは常にfmt
を使用します。- verb 'f', 'e', 'g', 'd' use localized formatting unless the '#' flag is specified.
- "
%d
" などのf
,e
,g
,d
動詞は、#
フラグが指定されない限り、地域化された書式を使用します。m
動詞は、引数の文字列の翻訳を挿入します。(※)その他のオプションについては
fmt
パッケージのドキュメントをご覧ください。
※ 【筆者注】 message
には国際化のための翻訳辞書機能があるようです。しかし、ドキュメントのサンプルが動かないため、使い方もよくわかりません。分かり次第追記か別記事にしたいと思います。
参考文献
- Localized Formatting | message | text | golang.org @ pkg.go.dev
- "How to fmt.Printf an integer with thousands comma" @ Stackoverflow