Goの_fmt.Printf
_は、数千のコンマを含む数値の出力をサポートしていますか?
fmt.Printf("%d", 1000)
は_1000
_を出力しますが、代わりに_1,000
_を出力するにはどの形式を指定できますか?
Fmt印刷動詞はどれも、千単位の区切り文字をサポートしていません。
使用する - golang.org/x/text/message
nicode CLDR の任意の言語のローカライズされたフォーマットを使用して印刷します。
package main
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
)
func main() {
p := message.NewPrinter(language.English)
p.Printf("%d\n", 1000)
// Output:
// 1,000
}
私は これのライブラリ と、他のいくつかの人間表現の懸念を書きました。
結果の例:
0 -> 0
100 -> 100
1000 -> 1,000
1000000000 -> 1,000,000,000
-100000 -> -100,000
使用例:
fmt.Printf("You owe $%s.\n", humanize.Comma(6582491))
Githubで、ユーザーが指定した3桁区切り、10進数区切り、10進数精度に従って数値(float64またはint)をレンダリングする関数のGoスニペットを公開しました。
https://Gist.github.com/gorhill/528519
使用法:s:= RenderFloat(format、n) formatパラメーターは、番号n。 の形式の例を示します。文字列、n = 12345.6789: "#、###。##" => "12,345.67" "#、###。" => "12,345" "#、###" => "12345,678" "#\ u202F ###、##" => "12 345,67" "#。###、###### => 12.345,678900 " "(別名デフォルト形式)=> 12,345.67
fmt
パッケージは、小数のグループ化をサポートしていません。
独自に実装する(または既存のものを使用する)必要があります。
コンパクトで非常に効率的なソリューションを次に示します(後の説明を参照)。
Go Playground で試してください。
_func Format(n int64) string {
in := strconv.FormatInt(n, 10)
out := make([]byte, len(in)+(len(in)-2+int(in[0]/'0'))/3)
if in[0] == '-' {
in, out[0] = in[1:], '-'
}
for i, j, k := len(in)-1, len(out)-1, 0; ; i, j = i-1, j-1 {
out[j] = in[i]
if i == 0 {
return string(out)
}
if k++; k == 3 {
j, k = j-1, 0
out[j] = ','
}
}
}
_
それをテストする:
_for _, v := range []int64{0, 1, 12, 123, 1234, 123456789} {
fmt.Printf("%10d = %12s\n", v, Format(v))
fmt.Printf("%10d = %12s\n", -v, Format(-v))
}
_
出力:
_ 0 = 0
0 = 0
1 = 1
-1 = -1
12 = 12
-12 = -12
123 = 123
-123 = -123
1234 = 1,234
-1234 = -1,234
123456789 = 123,456,789
-123456789 = -123,456,789
_
基本的にFormat()
関数が行うことは、グループ化せずに数値をフォーマットし、必要に応じて(グループの後)グループ化シンボルを挿入する数値の桁をコピーします(_','
_)桁数が多い場合は3桁の数字)一方、保持される負符号の世話をします。
出力の長さ:
基本的には、入力の長さと挿入されるグループ化記号の数です。グループ化記号の数は次のとおりです。
_numOfCommas = (numOfDigits - 1) / 3
_
入力文字列は数字(_'0..9'
_)とオプションで負符号(_'-'
_)のみを含むことができる数値であるため、文字はUTF-で1対1の方法でバイトに単純にマッピングされます8エンコード(Goが文字列をメモリに保存する方法です)。したがって、ルーン文字の代わりにバイトを使用するだけで済みます。したがって、桁数は入力文字列の長さであり、オプションで符号桁_1
_の_'-'
_を引いたものです。
符号桁がある場合は、_in[0]
_になります。 _'-'
_の数値は_45
_であり、数字の数値_'0'..'9'
_は_48..57
_です。したがって、符号文字は可能な数字よりも小さくなります。したがって、最初の文字(常に少なくとも1文字あります)を_'0'
_で除算すると、負符号の場合は_0
_が得られ、数字の場合は_1
_が得られます(整数除算) )。
したがって、入力文字列の桁数は次のとおりです。
_numOfDigits = len(in) - 1 + int(in[0]/'0')
_
したがって、グループ化記号の数:
_numOfCommas = (len(in) - 2 + int(in[0]/'0')) / 3
_
したがって、出力スライスは次のようになります。
_out := make([]byte, len(in)+(len(in)-2+int(in[0]/'0'))/3)
_
負符号文字の処理:
数値が負の場合、入力文字列をスライスして処理から除外し、符号ビットを出力に手動でコピーします。
_if in[0] == '-' {
in, out[0] = in[1:], '-'
}
_
したがって、関数の残りの部分は、オプションの負符号文字を知っている/気にする必要はありません。
関数の残りはfor
ループで、入力文字列から出力に数字のバイト(数字)をコピーし、3桁ごとにグループ化記号(_','
_)を挿入しますさらに桁がある場合。ループは下向きになるため、3桁のグループを追跡しやすくなります。完了すると(もう桁はありません)、出力バイトスライスはstring
として返されます。
効率をあまり気にせず、読みやすさを重視する場合は、このバージョンをお勧めします。
_func Format2(n int64) string {
if n < 0 {
return "-" + Format2(-n)
}
in := strconv.FormatInt(n, 10)
out := make([]byte, len(in)+(len(in)-1)/3)
for i, j, k := len(in)-1, len(out)-1, 0; ; i, j = i-1, j-1 {
out[j] = in[i]
if i == 0 {
return string(out)
}
if k++; k == 3 {
j, k = j-1, 0
out[j] = ','
}
}
}
_
基本的に、これは再帰呼び出しで負の数値を処理します。数値が負の場合、絶対値(正の値)で自身を(再帰的に)呼び出し、結果に_"-"
_文字列を付加します。
append()
スライスあり組み込みの append()
関数とスライス操作を使用する別のバージョンがあります。多少わかりやすいが、パフォーマンスに関してはそれほど良くない:
_func Format3(n int64) string {
if n < 0 {
return "-" + Format3(-n)
}
in := []byte(strconv.FormatInt(n, 10))
var out []byte
if i := len(in) % 3; i != 0 {
if out, in = append(out, in[:i]...), in[i:]; len(in) > 0 {
out = append(out, ',')
}
}
for len(in) > 0 {
if out, in = append(out, in[:3]...), in[3:]; len(in) > 0 {
out = append(out, ',')
}
}
return string(out)
}
_
最初のif
ステートメントは、存在する場合は3桁未満の最初のオプションの「不完全な」グループを処理し、後続のfor
ループは残りを処理し、各反復で3桁をコピーします。さらに桁がある場合は、コンマ(_','
_)グループ化記号を追加します。
以下は、整数とグループ化セパレーターを取り、指定されたセパレーターで区切られた文字列を返す関数です。私は、効率のために最適化を試みましたが、タイトループでは文字列の連結やmod/divisionはありません。私のプロファイリングから、それは私のMacのhumanize.Commas実装の2倍以上の速さです(〜680ns対1642ns)。私はGoが初めてなので、より高速な実装を楽しみにしています
使用法:s:= NumberToString(n int、sep rune)
例
Int値の範囲で検証された異なるセパレーター( '、' vs '')を使用して説明します。
s:= NumberToString(12345678、 '、')
=> "12,345,678"
s:= NumberToString(12345678、 '')
=> "12 345 678"
s:= NumberToString(-9223372036854775807、 '、')
=> "-9,223,372,036,854,775,807"
関数の実装
func NumberToString(n int, sep rune) string {
s := strconv.Itoa(n)
startOffset := 0
var buff bytes.Buffer
if n < 0 {
startOffset = 1
buff.WriteByte('-')
}
l := len(s)
commaIndex := 3 - ((l - startOffset) % 3)
if (commaIndex == 3) {
commaIndex = 0
}
for i := startOffset; i < l; i++ {
if (commaIndex == 3) {
buff.WriteRune(sep)
commaIndex = 0
}
commaIndex++
buff.WriteByte(s[i])
}
return buff.String()
}
正規表現を使用した簡単な関数を次に示します。
import (
"regexp"
)
func formatCommas(num int) string {
str := fmt.Sprintf("%d", num)
re := regexp.MustCompile("(\\d+)(\\d{3})")
for n := ""; n != str; {
n = str
str = re.ReplaceAllString(str, "$1,$2")
}
return str
}
例:
fmt.Println(formatCommas(1000))
fmt.Println(formatCommas(-1000000000))
出力:
1,000
-1,000,000,000
https://github.com/dustin/go-humanize を使用します。これらのことを処理するヘルパーがたくさんいます。 MiB、MB、およびその他のグッズとしてのバイトに加えて。
パッケージhumanizeは魔法をかけることができます!このパッケージのドキュメントを参照してください here 。このパッケージを使用するには、まずGit SCMなどのツールを使用してインストールします。 Git Bashを使用している場合は、シェルウィンドウを開いて次のように入力します。
go get -u github.com/dustin/go-humanize
これが完了すると、次のソリューションコードを使用できます(Say、main.go):
package main
import (
"fmt"
"github.com/dustin/go-humanize"
)
func main() {
fmt.Println(humanize.Commaf(float64(123456789)));
fmt.Println(humanize.Commaf(float64(-1000000000)));
fmt.Println(humanize.Commaf(float64(-100000.005)));
fmt.Println(humanize.Commaf(float64(100000.000)));
}
BigComma, Comma, BigCommaf
などのようなCommaf
には、入力のデータ型に依存する他のバリエーションがあります。
したがって、次のコマンドを使用してこのプログラムを実行すると:
go run main.go
次のようなoutputが表示されます。
123,456,789
-1,000,000,000
-100,000.005
100,000