6

値を考えてみましょうDecimal

Decimal value = -1234567890.1234789012M;

Decimalこの値を文字列に変換し、「数千の区切り文字」を含めたいと思います。

注:千の区切り文字を含めたくないので、数字のグループ化を含めたいと思います。この違いは、数字を数千にグループ化しない、またはグループを区切るためにコンマを使用しない文化にとって重要です。

私のコンピュータで、現在のロケールで、さまざまな標準フォーマット文字列を使用した出力例:

value.ToString()        =  -1234567890..1234789012   (Implicit General)
value.ToString("g")     =  -1234567890..1234789012   (General)
value.ToString("d")     =          FormatException   (Decimal whole number)
value.ToString("e")     =         -1..234568e++009   (Scientific)
value.ToString("f")     =         -1234567890..123   (Fixed Point)
value.ToString("n")     =     -12,,3456,,7890..123   (Number with commas for thousands)
value.ToString("r")     =          FormatException   (Round trippable)
value.ToString("c")     =   -$$12,,3456,,7890..123   (Currency)
value.ToString("#,0.#") =     -12,,3456,,7890..1

が欲しいのは(文化に応じて):

en-US      -1,234,567,890.1234789012
ca-ES      -1.234.567.890,1234789012
gsw-FR     -1 234 567 890,1234789012    (12/1/2012: fixed gws-FR to gsw-FR)
fr-CH      -1'234'567'890.1234789012
ar-DZ       1,234,567,890.1234789012-
prs-AF      1.234.567.890,1234789012-
ps-AF       1،234،567،890,1234789012-
as-IN     -1,23,45,67,890.1234789012
lo-LA      (1234567,890.1234789012)     (some debate if numbers should be "1,234,567,890")
qps-PLOC  12,,3456,,7890..1234789012

Decimal数字をグループ化して、を文字列に変換するにはどうすればよいですか?


更新:私の現在の文化を使用して、いくつかのより望ましい出力:

-1234567890M             -->   -12,,3456,,7890
-1234567890.1M           -->   -12,,3456,,7890..1
-1234567890.12M          -->   -12,,3456,,7890..12
-1234567890.123M         -->   -12,,3456,,7890..123
-1234567890.1234M        -->   -12,,3456,,7890..1234
-1234567890.12347M       -->   -12,,3456,,7890..12347
-1234567890.123478M      -->   -12,,3456,,7890..123478
-1234567890.1234789M     -->   -12,,3456,,7890..1234789
-1234567890.12347890M    -->   -12,,3456,,7890..1234789
-1234567890.123478901M   -->   -12,,3456,,7890..123478901
-1234567890.1234789012M  -->   -12,,3456,,7890..1234789012

更新一般形式をDecimal.ToString()使用して、表示する必要のあるすべての数字を表示する方法を確認してみました。

public override string ToString()
{
    return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo);
}

Number.FormatDecimalそれがどこかに隠されていることを除いて:

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern string FormatDecimal(decimal value, string format, NumberFormatInfo info);

これが行き止まりです。

4

3 に答える 3

7

小数のToStringメソッドは、デフォルトでユーザーのセッションにCultureInfo.CurrentCultureを使用するため、コードを実行しているユーザーによって異なります。

ToStringメソッドは、さまざまなオーバーロードでIFormatProviderも受け入れます。ここで、カルチャ固有のフォーマッタを提供する必要があります。

たとえば、fr-CHのNumberFormatを渡すと、そのカルチャが期待するとおりにフォーマットできます。

var culture = CultureInfo.CreateSpecificCulture("fr-CH");
Decimal value = -1234567890.1234789012M;

Console.WriteLine(value.ToString("##,#.###############", culture.NumberFormat));

出力します

 -1'234'567'890.1234789012

編集#3-カスタムフォーマッターを使用して書き直しました。これは、新しく更新された質問に基づいて、あなたが望むことをするはずです。

編集#4-すべての入力を取得し、これを実行しました:

public void TestOutput()
{
    PrintValue(-1234567890M);
    PrintValue(-1234567890.1M);
    PrintValue(-1234567890.12M);
    PrintValue(-1234567890.123M);
    PrintValue(-1234567890.1234M);
    PrintValue(-1234567890.12347M);
    PrintValue(-1234567890.123478M);
    PrintValue(-1234567890.1234789M);
    PrintValue(-1234567890.12347890M);
    PrintValue(-1234567890.123478901M);
    PrintValue(-1234567890.1234789012M);
}

private static void PrintValue(decimal value)
{
   var culture = CultureInfo.CreateSpecificCulture("qps-PLOC");
   Console.WriteLine(value.ToString("##,#.###############", culture.NumberFormat));
}

指定したものと一致する出力を提供します。

--12,,3456,,7890
--12,,3456,,7890..1
--12,,3456,,7890..12
--12,,3456,,7890..123
--12,,3456,,7890..1234
--12,,3456,,7890..12347
--12,,3456,,7890..123478
--12,,3456,,7890..1234789
--12,,3456,,7890..1234789
--12,,3456,,7890..123478901
--12,,3456,,7890..1234789012

Joshuaが指摘したように、これは一部のロケールでのみ機能します。

その外観から、2つの悪のうち、小さい方を選択する必要があります。数値の精度を知ること、または各文化の形式を指定することです。あなたの数字の精度がもっと簡単かもしれないことを知って賭けたいと思います。その場合、私の答えの以前のバージョンが役立つかもしれません:

出力する小数点以下の桁数を明示的に制御するには、カルチャによって提供される数値形式を複製し、NumberDecimalDigitsプロパティを変更します。

var culture = CultureInfo.CreateSpecificCulture("fr-CH");
Decimal value = -1234567890.1234789012M;
NumberFormatInfo format = (NumberFormatInfo)culture.NumberFormat.Clone();
format.NumberDecimalDigits = 30;

Console.WriteLine(value.ToString("n", format));

これは以下を出力します:

-1'234'567'890.123478901200000000000000000000
于 2012-07-10T14:34:37.923 に答える
5

カスタムパターンを指定できます(パターンは、カルチャ固有のグループ化方法と、適切なグループ化および小数点記号文字に適切に解決されます)。パターンには、正、負、およびゼロのセクションを含めることができます。ポジティブパターンは常に同じですが、ネガティブパターンはカルチャに依存し、NumberFormatInfoのNumberNegativePatternプロパティから取得できます。できるだけ高い精度が必要なため、小数点以下28桁のプレースホルダーを入力する必要があります。カンマはグループ化を強制します。

    public static class DecimalFormatters
    {
        public static string ToStringNoTruncation(this Decimal n, IFormatProvider format)
        {
            NumberFormatInfo nfi = NumberFormatInfo.GetInstance(format);
            string[] numberNegativePatterns = {
                    "(#,0.############################)", //0:  (n)
                    "-#,0.############################",  //1:  -n
                    "- #,0.############################", //2:  - n
                    "#,0.############################-",  //3:  n-
                    "#,0.############################ -"};//4:  n -
            var pattern = "#,0.############################;" + numberNegativePatterns[nfi.NumberNegativePattern];
            return n.ToString(pattern, format);
        }

        public static string ToStringNoTruncation(this Decimal n)
        {
            return n.ToStringNoTruncation(CultureInfo.CurrentCulture);
        }
    }

サンプル出力

Locale    Output
========  ============================
en-US     -1,234,567,890.1234789012
ca-ES     -1.234.567.890,1234789012
hr-HR     - 1.234.567.890,1234789012
gsw-FR    -1 234 567 890,1234789012
fr-CH     -1'234'567'890.1234789012
ar-DZ     1,234,567,890.1234789012-
prs-AF    1.234.567.890,1234789012-
ps-AF     1،234،567،890,1234789012-
as-IN     -1,23,45,67,890.1234789012
lo-LA     (1234567,890.1234789012)
qps-PLOC  -12,,3456,,7890..1234789012

現在、NegativeNumberFormat4(n -)を使用するロケールがないため、ケースをテストできません。しかし、それが失敗すると考える理由はありません。

于 2012-07-16T22:02:22.460 に答える
2

文字列をフォーマットするときは、カルチャを含める必要があります。String.Formatを使用してカルチャを最初のパラメータとして含めるか、オブジェクトのToStringメソッドを使用してカルチャを取得するオーバーロードを使用することができます。

次のコードは、期待される出力を生成します(gws-FRを除いて、その文字列を持つカルチャを見つけることができませんでした)。

namespace CultureFormatting {
  using System;
  using System.Globalization;

  class Program {
    public static void Main() {
      Decimal value = -1234567890.1234789012M;
      Print("en-US", value);
      Print("ca-ES", value);
      //print("gws-FR", value);
      Print("fr-CH", value);
      Print("ar-DZ", value);
      Print("prs-AF", value);
      Print("ps-AF", value);
      Print("as-IN", value);
      Print("lo-LA", value);
      Print("qps-PLOC", value);
    }

    static void Print(string cultureName, Decimal value) {
      CultureInfo cultureInfo = new CultureInfo(cultureName);
      cultureInfo.NumberFormat.NumberDecimalDigits = 10;
      // Or, you could replace the {1:N} with {1:N10} to do the same
      // for just this string format call.
      string result = 
        String.Format(cultureInfo, "{0,-8} {1:N}", cultureName, value);
      Console.WriteLine(result);
    }
  }
}

上記のコードは、次の出力を生成します。

en-US    -1,234,567,890.1234789012
ca-ES    -1.234.567.890,1234789012
fr-CH    -1'234'567'890.1234789012
ar-DZ    1,234,567,890.1234789012-
prs-AF   1.234.567.890,1234789012-
ps-AF    1،234،567،890,1234789012-
as-IN    -1,23,45,67,890.1234789012
lo-LA    (1234567,890.1234789012)
qps-PLOC --12,,3456,,7890..1234789012

ASP.Netなどのマルチスレッドシステムを使用している場合は、スレッドのCurrentCultureプロパティを変更できます。スレッドのカルチャを変更すると、関連付けられたすべてのToString呼び出しString.Formatでそのカルチャを使用できるようになります。

アップデート

すべての精度を表示したいので、少し作業を行う必要があります。NumberFormat.NumberDecimalDigits値の精度が低い場合を除いて、を使用すると機能しますが、数値は末尾のゼロで出力されます。すべての桁を余分なものなしで表示する必要がある場合は、文字列に変換する前に、事前に精度を計算して設定する必要があります。StackOverflowの質問であるCalculateSystem.DecimalPrecision and Scaleは、小数の精度を判断するのに役立つ場合があります。

于 2012-07-10T14:40:06.063 に答える