260

"3.5"double のような文字列を解析したい。でも、

double.Parse("3.5") 

35 が得られ、

double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint) 

をスローしFormatExceptionます。

現在、私のコンピューターのロケールはドイツ語に設定されており、カンマが小数点として使用されています。それを使って何かをしなければならず、入力としてdouble.Parse()期待しているかもしれませんが"3,5"、よくわかりません。

現在のロケールで指定されているようにフォーマットされている場合とされていない場合がある 10 進数を含む文字列を解析するにはどうすればよいですか?

4

18 に答える 18

474
double.Parse("3.5", CultureInfo.InvariantCulture)
于 2009-08-30T21:16:37.900 に答える
32

コメントが書けなかったので、ここに書きます。

double.Parse("3.5", CultureInfo.InvariantCulture)は良い考えではありません。なぜなら、カナダでは 3.5 ではなく 3,5 と書き、この関数は結果として 35 を返すからです。

私は自分のコンピューターで両方をテストしました:

double.Parse("3.5", CultureInfo.InvariantCulture) --> 3.5 OK
double.Parse("3,5", CultureInfo.InvariantCulture) --> 35 not OK

これは、ピエール・アラン・ヴィジャンが言及した正しい方法です

public static double GetDouble(string value, double defaultValue)
{
    double result;

    // Try parsing in the current culture
    if (!double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.CurrentCulture, out result) &&
        // Then try in US english
        !double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result) &&
        // Then in neutral language
        !double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out result))
    {
        result = defaultValue;
    }
    return result;
}
于 2016-03-18T16:38:56.750 に答える
25
Double.Parse("3,5".Replace(',', '.'), CultureInfo.InvariantCulture)

解析する前にコンマをポイントに置き換えます。小数点としてコンマを使用する国で役立ちます。ユーザー入力 (必要な場合) を 1 つのコンマまたはポイントに制限することを検討してください。

于 2009-10-15T13:49:45.043 に答える
15

秘訣は、インバリアント カルチャを使用して、すべてのカルチャでドットを解析することです。

double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.NumberFormatInfo.InvariantInfo);
于 2009-08-30T21:19:52.840 に答える
3
string testString1 = "2,457";
string testString2 = "2.457";    
double testNum = 0.5;
char decimalSepparator;
decimalSepparator = testNum.ToString()[1];

Console.WriteLine(double.Parse(testString1.Replace('.', decimalSepparator).Replace(',', decimalSepparator)));
Console.WriteLine(double.Parse(testString2.Replace('.', decimalSepparator).Replace(',', decimalSepparator)));
于 2012-10-15T10:15:19.523 に答える
2

このトピックに関する私の 2 セントは、一般的な double 変換メソッドを提供しようとしています。

private static double ParseDouble(object value)
{
    double result;

    string doubleAsString = value.ToString();
    IEnumerable<char> doubleAsCharList = doubleAsString.ToList();

    if (doubleAsCharList.Where(ch => ch == '.' || ch == ',').Count() <= 1)
    {
        double.TryParse(doubleAsString.Replace(',', '.'),
            System.Globalization.NumberStyles.Any,
            CultureInfo.InvariantCulture,
            out result);
    }
    else
    {
        if (doubleAsCharList.Where(ch => ch == '.').Count() <= 1
            && doubleAsCharList.Where(ch => ch == ',').Count() > 1)
        {
            double.TryParse(doubleAsString.Replace(",", string.Empty),
                System.Globalization.NumberStyles.Any,
                CultureInfo.InvariantCulture,
                out result);
        }
        else if (doubleAsCharList.Where(ch => ch == ',').Count() <= 1
            && doubleAsCharList.Where(ch => ch == '.').Count() > 1)
        {
            double.TryParse(doubleAsString.Replace(".", string.Empty).Replace(',', '.'),
                System.Globalization.NumberStyles.Any,
                CultureInfo.InvariantCulture,
                out result);
        }
        else
        {
            throw new ParsingException($"Error parsing {doubleAsString} as double, try removing thousand separators (if any)");
        }
    }

    return result;
}

期待どおりに動作します:

  • 1.1
  • 1,1
  • 10億
  • 1.000.000.000
  • 1,000,000,000.99
  • 1.000.000.000,99
  • 5,000,111.3
  • 5.000.111,3
  • 0.99,000,111,88
  • 0,99.000.111.88

1.3,14デフォルトの変換は実装されていないため、 の解析に失敗し1,3.14たり、同様のケースが発生したりします。

于 2018-12-25T16:39:17.220 に答える
1

値がユーザー入力からのものである場合、100%正しい変換は不可能だと思います。たとえば、値が123.456の場合、グループ化することも、小数点にすることもできます。本当に100%が必要な場合は、フォーマットを記述し、正しくない場合は例外をスローする必要があります。

しかし、私はJanWのコードを改善したので、100%に少し先んじています。背後にある考え方は、最後の区切り文字がgroupSeperatorの場合、これはdoubleではなく整数型になるということです。

追加されたコードは、GetDoubleの最初のifにあります。

void Main()
{
    List<string> inputs = new List<string>() {
        "1.234.567,89",
        "1 234 567,89",
        "1 234 567.89",
        "1,234,567.89",
        "1234567,89",
        "1234567.89",
        "123456789",
        "123.456.789",
        "123,456,789,"
    };

    foreach(string input in inputs) {
        Console.WriteLine(GetDouble(input,0d));
    }

}

public static double GetDouble(string value, double defaultValue) {
    double result;
    string output;

    // Check if last seperator==groupSeperator
    string groupSep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator;
    if (value.LastIndexOf(groupSep) + 4 == value.Count())
    {
        bool tryParse = double.TryParse(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.CurrentCulture, out result);
        result = tryParse ? result : defaultValue;
    }
    else
    {
        // Unify string (no spaces, only . )
        output = value.Trim().Replace(" ", string.Empty).Replace(",", ".");

        // Split it on points
        string[] split = output.Split('.');

        if (split.Count() > 1)
        {
            // Take all parts except last
            output = string.Join(string.Empty, split.Take(split.Count()-1).ToArray());

            // Combine token parts with last part
            output = string.Format("{0}.{1}", output, split.Last());
        }
        // Parse double invariant
        result = double.Parse(output, System.Globalization.CultureInfo.InvariantCulture);
    }
    return result;
}
于 2012-02-08T08:14:22.637 に答える
1

次のコードは、どのシナリオでもジョブを実行します。少し解析です。

List<string> inputs = new List<string>()
{
    "1.234.567,89",
    "1 234 567,89",
    "1 234 567.89",
    "1,234,567.89",
    "123456789",
    "1234567,89",
    "1234567.89",
};
string output;

foreach (string input in inputs)
{
    // Unify string (no spaces, only .)
    output = input.Trim().Replace(" ", "").Replace(",", ".");

    // Split it on points
    string[] split = output.Split('.');

    if (split.Count() > 1)
    {
        // Take all parts except last
        output = string.Join("", split.Take(split.Count()-1).ToArray());

        // Combine token parts with last part
        output = string.Format("{0}.{1}", output, split.Last());
    }

    // Parse double invariant
    double d = double.Parse(output, CultureInfo.InvariantCulture);
    Console.WriteLine(d);
}
于 2010-08-20T21:16:32.173 に答える
0

すべての解析でロケールを指定する必要がある代わりに、アプリケーション全体のロケールを設定することを好みますが、文字列形式がアプリ全体で一貫していない場合、これは機能しない可能性があります。

CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("pt-PT");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("pt-PT");

アプリケーションの先頭でこれを定義すると、すべての二重解析で小数点としてカンマが必要になります。適切なロケールを設定して、解析する文字列に小数点と千の区切り記号が適合するようにすることができます。

于 2015-04-17T09:21:49.310 に答える
0

@JanW のコードも改善しました...

医療機器からの結果をフォーマットするために必要で、">1000"、"23.3e02"、"350E-02"、および "NEGATIVE" も送信します。

private string FormatResult(string vResult)
{
  string output;
  string input = vResult;

  // Unify string (no spaces, only .)
  output = input.Trim().Replace(" ", "").Replace(",", ".");

  // Split it on points
  string[] split = output.Split('.');

  if (split.Count() > 1)
  {
    // Take all parts except last
    output = string.Join("", split.Take(split.Count() - 1).ToArray());

    // Combine token parts with last part
    output = string.Format("{0}.{1}", output, split.Last());
  }
  string sfirst = output.Substring(0, 1);

  try
  {
    if (sfirst == "<" || sfirst == ">")
    {
      output = output.Replace(sfirst, "");
      double res = Double.Parse(output);
      return String.Format("{1}{0:0.####}", res, sfirst);
    }
    else
    {
      double res = Double.Parse(output);
      return String.Format("{0:0.####}", res);
    }
  }
  catch
  {
    return output;
  }
}
于 2012-02-21T11:20:53.623 に答える
0

どの小数点記号を探すかを指定しないと難しいですが、そうする場合は、これが私が使用しているものです。

    public static double Parse(string str, char decimalSep)
    {
        string s = GetInvariantParseString(str, decimalSep);
        return double.Parse(s, System.Globalization.CultureInfo.InvariantCulture);
    }

    public static bool TryParse(string str, char decimalSep, out double result)
    {
        // NumberStyles.Float | NumberStyles.AllowThousands got from Reflector
        return double.TryParse(GetInvariantParseString(str, decimalSep), NumberStyles.Float | NumberStyles.AllowThousands, System.Globalization.CultureInfo.InvariantCulture, out result);
    }

    private static string GetInvariantParseString(string str, char decimalSep)
    {
        str = str.Replace(" ", "");

        if (decimalSep != '.')
            str = SwapChar(str, decimalSep, '.');

        return str;
    }
    public static string SwapChar(string value, char from, char to)
    {
        if (value == null)
            throw new ArgumentNullException("value");

        StringBuilder builder = new StringBuilder();

        foreach (var item in value)
        {
            char c = item;
            if (c == from)
                c = to;
            else if (c == to)
                c = from;

            builder.Append(c);
        }
        return builder.ToString();
    }

    private static void ParseTestErr(string p, char p_2)
    {
        double res;
        bool b = TryParse(p, p_2, out res);
        if (b)
            throw new Exception();
    }

    private static void ParseTest(double p, string p_2, char p_3)
    {
        double d = Parse(p_2, p_3);
        if (d != p)
            throw new Exception();
    }

    static void Main(string[] args)
    {
        ParseTest(100100100.100, "100.100.100,100", ',');
        ParseTest(100100100.100, "100,100,100.100", '.');
        ParseTest(100100100100, "100.100.100.100", ',');
        ParseTest(100100100100, "100,100,100,100", '.');
        ParseTestErr("100,100,100,100", ',');
        ParseTestErr("100.100.100.100", '.');
        ParseTest(100100100100, "100 100 100 100.0", '.');
        ParseTest(100100100.100, "100 100 100.100", '.');
        ParseTest(100100100.100, "100 100 100,100", ',');
        ParseTest(100100100100, "100 100 100,100", '.');
        ParseTest(1234567.89, "1.234.567,89", ',');    
        ParseTest(1234567.89, "1 234 567,89", ',');    
        ParseTest(1234567.89, "1 234 567.89",     '.');
        ParseTest(1234567.89, "1,234,567.89",    '.');
        ParseTest(1234567.89, "1234567,89",     ',');
        ParseTest(1234567.89, "1234567.89",  '.');
        ParseTest(123456789, "123456789", '.');
        ParseTest(123456789, "123456789", ',');
        ParseTest(123456789, "123.456.789", ',');
        ParseTest(1234567890, "1.234.567.890", ',');
    }

これは、どの文化でも機能するはずです。スワップの代わりに置き換える実装とは異なり、複数の小数点記号を持つ文字列の解析に正しく失敗します。

于 2015-07-28T09:16:46.920 に答える
-7

数を掛けてから、前に掛けたもので割ります。

例えば、

perc = double.Parse("3.555)*1000;
result = perc/1000
于 2016-03-08T19:02:55.560 に答える