web-dev-qa-db-ja.com

数千のコンマを含む整数をfmt.Printfする方法

Goの_fmt.Printf_は、数千のコンマを含む数値の出力をサポートしていますか?

fmt.Printf("%d", 1000)は_1000_を出力しますが、代わりに_1,000_を出力するにはどの形式を指定できますか?

docs はコンマに言及していないようで、 source にはすぐに何も表示されませんでした。

51
BrandonAGr

Fmt印刷動詞はどれも、千単位の区切り文字をサポートしていません。

25
zzzz

使用する - golang.org/x/text/messagenicode 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
}
46
dolmen

私は これのライブラリ と、他のいくつかの人間表現の懸念を書きました。

結果の例:

0 -> 0
100 -> 100
1000 -> 1,000
1000000000 -> 1,000,000,000
-100000 -> -100,000

使用例:

fmt.Printf("You owe $%s.\n", humanize.Comma(6582491))
46
Dustin

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 
11
R. Hill

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桁をコピーします。さらに桁がある場合は、コンマ(_','_)グループ化記号を追加します。

11
icza

以下は、整数とグループ化セパレーターを取り、指定されたセパレーターで区切られた文字列を返す関数です。私は、効率のために最適化を試みましたが、タイトループでは文字列の連結や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()
}
7
Ivan Tung

正規表現を使用した簡単な関数を次に示します。

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://play.golang.org/p/vnsAV23nUXv

2
jchavannes

https://github.com/dustin/go-humanize を使用します。これらのことを処理するヘルパーがたくさんいます。 MiB、MB、およびその他のグッズとしてのバイトに加えて。

1
abourget

パッケージ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
0