73

Gofmt.Printfは 3000 のコンマを含む数値の出力をサポートしていますか?

fmt.Printf("%d", 1000)outputs 、代わり1000に出力するためにどの形式を指定できますか?1,000

ドキュメントにはコンマについて言及されていないようで、すぐにソースに何も表示されませんでし

4

14 に答える 14

54

私はこのためのライブラリと、他のいくつかの人間表現に関する懸念事項を作成しました。

結果の例:

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

使用例:

fmt.Printf("You owe $%s.\n", humanize.Comma(6582491))
于 2012-10-23T00:24:24.313 に答える
26

fmt 印刷動詞は、3 桁ごとの区切り文字をサポートしていません。

于 2012-10-22T21:54:41.603 に答える
18

序文:私はこのユーティリティを でさらにカスタマイズしてリリースしました。github.com/icza/goxを参照してくださいfmtx.FormatInt()


パッケージは小数のfmtグループ化をサポートしていません。

自分で実装する (または既存のものを使用する) 必要があります。

コード

コンパクトで非常に効率的なソリューションを次に示します (後の説明を参照)。

Go Playgroundで試してみてください。

func Format(n int64) string {
    in := strconv.FormatInt(n, 10)
    numOfDigits := len(in)
    if n < 0 {
        numOfDigits-- // First character is the - sign (not a digit)
    }
    numOfCommas := (numOfDigits - 1) / 3

    out := make([]byte, len(in)+numOfCommas)
    if n < 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

説明:

基本的に、関数が行うことは、グループ化せずに数値をフォーマットし、十分な大きさの他のスライスを作成し、必要に応じて (数字がさらにある場合は 3 の数字のグループの後) 必要に応じてグループ化記号Format()を挿入して数字の数字をコピーすることです。','保持される負の符号に注意してください。

出力の長さ:

基本的には、入力の長さに挿入するグループ化記号の数を加えた長さです。グループ化記号の数は次のとおりです。

numOfCommas = (numOfDigits - 1) / 3

入力文字列は数字 ( '0..9') とオプションでマイナス記号 ( '-') のみを含む数値であるため、文字は単純に UTF-8 エンコーディングで 1 対 1 の方法でバイトにマップされます (これは Go が文字列をメモリー)。そのため、ルーンの代わりにバイトを簡単に操作できます。したがって、桁数は入力文字列の長さであり1、数値が負の場合はオプションでマイナスになります。

numOfDigits := len(in)
if n < 0 {
    numOfDigits-- // First character is the - sign (not a digit)
}

したがって、グループ化記号の数:

numOfCommas := (numOfDigits - 1) / 3

したがって、出力スライスは次のようになります。

out := make([]byte, len(in)+numOfCommas)

負符号文字の処理:

数値が負の場合、入力文字列をスライスして処理から除外し、手動で符号ビットを出力にコピーします。

if n < 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)
    numOfCommas := (len(in) - 1) / 3

    out := make([]byte, len(in)+numOfCommas)

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

于 2015-06-25T09:27:43.583 に答える
14

ユーザー指定の桁区切り記号、小数点記号、および小数点以下の精度に従って数値 (float64 または int) をレンダリングする関数の Go スニペットを Github に公開しました。

https://gist.github.com/gorhill/5285193

使用法: 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
于 2013-04-01T14:30:50.113 に答える
4

以前の回答で提供されたソリューションのパフォーマンスに興味を持ち、それらのベンチマークを使用してテストを作成しました。これには、私の 2 つのコード スニペットが含まれます。次の結果は、MacBook 2018、i7 2.6GHz で測定されました。

+---------------------+-------------------------------------------+--------------+
|       Author        |                Description                |    Result    |
|---------------------|-------------------------------------------|--------------|
| myself              | dividing by 1,000 and appending groups    |  3,472 ns/op |
| myself              | inserting commas to digit groups          |  2,662 ns/op |
| @icza               | collecting digit by digit to output array |  1,695 ns/op |
| @dolmen             | copying digit groups to output array      |  1,797 ns/op |
| @Ivan Tung          | writing digit by digit to buffer          |  2,753 ns/op |
| @jchavannes         | inserting commas using a regexp           | 63,995 ns/op |
| @Steffi Keran Rani, | using github.com/dustin/go-humanize       |  3,525 ns/op |
|  @abourget, @Dustin |                                           |              |
| @dolmen             | using golang.org/x/text/message           | 12,511 ns/op |
+---------------------+-------------------------------------------+--------------+
  • 最速のソリューションが必要な場合は、@icza のコード スニペットを入手してください。3 桁のグループではなく、1 桁ずつ進みますが、最速であることがわかりました。
  • 合理的な最短のコード スニペットが必要な場合は、以下のコードを参照してください。最速のソリューションの半分以上の時間が追加されますが、コードは 3 倍短くなります。
  • ワンライナーが必要で、外部ライブラリの使用を気にしない場合は、github.com/dustin/go-humanizeにアクセスしてください。これは最速のソリューションの 2 倍以上遅くなりますが、ライブラリは他のフォーマットで役立つ場合があります。
  • ローカライズされた出力が必要な場合は、golang.org/x/text/messageを選択してください。最速のソリューションよりも 7 倍遅くなりますが、消費者の言語に合わせるという贅沢は無料ではありません。

他の手作業でコーディングされたソリューションも高速であり、regexp の使用を除いて、どれを選択しても後悔することはありません。regexp を使用するには最短のコード スニペットが必要ですが、パフォーマンスが非常に悪く、その価値はありません。

このトピックへの私の貢献は、プレイグラウンドで実行してみることができます:

func formatInt(number int) string {
    output := strconv.Itoa(number)
    startOffset := 3
    if number < 0 {
        startOffset++
    }
    for outputIndex := len(output); outputIndex > startOffset; {
        outputIndex -= 3
        output = output[:outputIndex] + "," + output[outputIndex:]
    }
    return output
}
于 2020-05-02T14:12:35.583 に答える
2

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

于 2015-06-12T01:20:29.750 に答える
-2

ライブラリを使用したくない場合 (何らかの理由で)、私はこれをノックアップしました。動作しているようで、指定されたルーンを区切り文字として使用できます。

import (
    "strconv"
)

func delimitNumeral(i int, delim rune) string {

    src := strconv.Itoa(i)
    strLen := utf8.RuneCountInString(src)
    outStr := ""
    digitCount := 0
    for i := strLen - 1; i >= 0; i-- {

        outStr = src[i:i+1] + outStr
        if digitCount == 2 {
            outStr = string(delim) + outStr
            digitCount = 0
        } else {
            digitCount++
        }
    }

    return outStr
}

注:さらにテストした結果、この機能は完全には機能しません。@IvanTung によって投稿されたソリューションを使用することをお勧めします。また、私のものを完全に機能させることができる人からの編集を歓迎します。

于 2015-06-02T15:58:00.870 に答える
-3
import ("fmt"; "strings")

func commas(s string) string {
    if len(s) <= 3 {
        return s
    } else {
        return commas(s[0:len(s)-3]) + "," + s[len(s)-3:]
    }
}

func toString(f float64) string {
    parts := strings.Split(fmt.Sprintf("%.2f", f), ".")
    if parts[0][0] == '-' {
        return "-" + commas(parts[0][1:]) + "." + parts[1]
    }
    return commas(parts[0]) + "." + parts[1]
}
于 2016-11-18T11:52:56.753 に答える