我想将"3.5"之类的字符串解析为双精度型。但是,

double.Parse("3.5") 


产量35和

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


抛出FormatException

>现在,我的计算机的语言环境设置为德语,其中逗号用作小数点分隔符。它可能与double.Parse()有关,并且期望"3,5"作为输入,但是我不确定。

我如何解析包含十进制数字的字符串,该字符串可能会或可能不会按照我当前的语言环境?

评论

小数逗号肯定会影响输出。

如果适合您的情况,请不要忘记使用double.TryParse()方法。

#1 楼

double.Parse("3.5", CultureInfo.InvariantCulture)


评论


我喜欢使用XmlConvert类...与使用CultureInfo.InvariantCulture相比,这是否更好,更坏和/或不同,您是否有任何想法?

– ChristW
09年8月30日在21:23

好吧,XmlConvert并不是真正用于解析代码中的单个double值。我更喜欢使用double.Parse或Convert.ToDouble,这使我的意图显而易见。

–梅尔达德·阿夫沙里(Mehrdad Afshari)
09年8月30日在21:29

这意味着doulble.Parse使用默认区域性,该区域性可能不包含点作为小数点?

–艾默德·赛义德(Ahmed Said)
09年8月30日在22:32

如果转换12345678.12345678,它也会转换12345678.123457

– PUG
2011年12月2日于16:18

不适用于我:跳过逗号并返回和int为double

– fnc12
15年7月8日在15:44

#2 楼

我通常使用多区域性函数来解析用户输入,主要是因为如果某人习惯于数字键盘,并且使用的是使用逗号作为小数点分隔符的区域性,那么该人将使用数字键盘的点而不是逗号。

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;
}


请注意,@ nikie的注释是正确的。为了我的辩护,我在受控的环境中使用此功能,因为我知道该文化可以是en-US,en-CA或fr-CA。我之所以使用此函数,是因为在法语中,我们使用逗号作为小数点分隔符,但是从事过金融业的任何人都将始终在数字键盘上使用小数点分隔符,但这是一个要点,而不是逗号。因此,即使在fr-CA文化中,我也需要解析将点作为小数点分隔符的数字。

评论


我不确定这是个好主意。如果您不了解文化,就无法可靠地解析双精度型:在德国,双精度型值可能包含'。',但在那里它们被视为数千个分隔符。因此,在Legate的情况下,GetDouble(“ 3.5”)在德语语言环境中将返回35,在使用环境中将返回3.5。

–尼基
09-10-15在13:58

不,皮埃尔·阿兰(Pierre Alain)是对的,因为它完全符合书面要求。如果您的文化说“点是一千”分隔符,那么“ 3.5”将被视为“ 35”,这很好。但是,如果您对“点”不遵循任何规则,那么该字符将被解析为小数点,并且也可以使用。我本来会避免尝试enUS文化,但这是个人选择。

–xryl669
13年4月10日在15:33

如果您在带逗号的文化中使用小键盘,则点号将设置为逗号。

–CrazyBaran
17年8月25日在9:59

小键盘的小数点分隔符取决于键盘布局(而不是区域设置-至少在Windows 7上是这样)(我使用匈牙利语编写文本,电子邮件...,并使用美国英语编写代码,因此它可以是点或逗号。我还使用自定义的区域设置,将小数点分隔符从“,”更改为“。”,并将列表分隔符从“;”更改为“,”。您知道,导致csv ...祝大家好运! -文化应用程序;)

–史蒂文·斯帕克(Steven Spark)
18年6月22日在13:15

如果系统文化使用逗号作为分隔符,则此代码不适用于100.35之类的数字。您期望它返回大约100的数字,但它返回10035。

–Lennart
8月6日11:31

#3 楼

我无法发表评论,所以我在这里写:

double.Parse(“ 3.5”,CultureInfo.InvariantCulture)不是一个好主意,因为在加拿大,我们写的是3,5而不是3.5结果这个函数得到35。

我在计算机上都进行了测试:

提到了Alain Vigeant

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


评论


回复:“ ...因为在加拿大,我们写的是3,5而不是3.5”,您确定吗?根据小数点表示:“将点“。”用作小数点的国家包括...加拿大(使用英语时)。它不是更多关于使用法语版本的Windows吗?

– Peter Mortensen
16-11-21在16:57



贝贝因为法语版本。在蒙特利尔,我们写3,5而不是3.5

– Malus Jan
16年11月23日在3:43

因此,根据您的逻辑,总是只有其中1个返回true?

–艾米尔
17-10-9在0:56

看它

– Malus Jan
17-10-9在19:19

仍然有一个错误。对于输入字符串,如GetDouble(“ 10 , 0”,0.0)。提及的函数返回100。

– Krivers
18年8月14日在3:56



#4 楼

Double.Parse("3,5".Replace(',', '.'), CultureInfo.InvariantCulture)


在解析之前用点替换逗号。在使用逗号作为小数点分隔符的国家/地区有用。考虑将用户输入(如有必要)限制为一个逗号或点。

评论


正确答案要比拥有+133票的答案正确得多。它可以在带有“,”或“”的两个系统上使用。小数点分隔符...

– Badiboy
2014年6月11日15:14

@Badiboy您能解释一下这个答案有什么问题吗?据我了解,InvariantCulture始终带有“。”。作为小数点分隔符。因此,它对两个系统均适用。

– Alex P.
2014年6月26日20:10

@ Alex11223你是对的。这就是为什么我说这个答案要好于流行的答案。 PS:如果您使用“,”作为列表分隔符(即1,234,560.01),那么友好地讲这段代码也会失败,但是我完全不知道如何解决这个问题。 :)

– Badiboy
2014年6月27日下午4:56

这不是一个好答案,因为在某些CultureInfos中,是千位分隔符,可以使用。如果将其替换为一个点,则最终将具有多个点,并且解析将失败:Double.Parse((12345.67).ToString(“ N”,new CultureInfo(“ en”))。Replace(',','。 '),CultureInfo.InvariantCulture),因为(12345.67).ToString(“ N”,new CultureInfo(“ en”))。Replace(',','。')的格式将为“ 12.345.67”

–codingdave
18-2-27在11:18

1,234.56-> 1.234.56不是解析器。另一个想法是检查数字是否包含“。”和','并将','替换为空字符串,如果仅显示','逗号,则将其替换为'。

– GDocal
19年8月7日在13:49



#5 楼

诀窍是使用不变区域性,以解析所有区域中的点。

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


#6 楼

看,以上所有建议用常量字符串替换字符串的答案都是错误的。为什么?因为您不遵守Windows的区域设置! Windows确保用户可以自由设置自己想要的分隔符。他/他可以打开控制面板,进入区域面板,单击高级并随时更改字符。即使在程序运行期间。想想看。一个好的解决方案必须意识到这一点。

因此,首先,您必须问自己,这个数字来自何处,要解析。如果它来自.NET Framework中的输入,则没有问题,因为它将采用相同的格式。但是它可能来自外部,可能来自外部服务器,也可能来自仅支持字符串属性的旧数据库。在那里,数据库管理员应该给出一个规则,以数字格式存储数字。例如,如果您知道它将是具有US格式的US DB,则可以使用以下代码:并且请不要使用“ Convert.ToXxxx”。 “转换”类仅被视为在任何方向进行转换的基础。此外:您也可以对DateTimes使用类似的机制。

评论


同意!尝试手动实现区域性功能最终会导致您出乎意料的情况以及令人头疼的问题。让.NET正确处理它。

–哈洛斯
15年7月4日在16:48

一个大问题是,当用户使用的小数点分隔符不被视为其文化设置的小数点分隔符时

–EdmundYeung99
2015年9月30日,下午1:28

#7 楼

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)));


#8 楼

以下代码可在任何情况下完成该任务。有点解析。

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);
}


评论


1.234.567.890将返回1234567.890

– Dan Vogel
11年8月23日在17:39

我还没有尝试过,但是如果您在不同文化的SO中执行该应用程序,那么我认为此代码不会成功:/

– Dani bISHOP
2012年5月30日15:59

#9 楼

我认为,如果该值来自用户输入,则不可能100%正确地进行转换。例如如果值为123.456,则它可以是分组,也可以是小数点。如果您确实需要100%,则必须描述格式并在不正确的情况下引发异常。

但是我改进了JanW的代码,因此我们可以进一步提高100% 。背后的想法是,如果最后一个分隔符是groupSeperator,则它将是整数类型,而不是双精度类型。

添加的代码在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;
}


#10 楼

        var doublePattern = @"(?<integer>[0-9]+)(?:\,|\.)(?<fraction>[0-9]+)";
        var sourceDoubleString = "03444,44426";
        var match = Regex.Match(sourceDoubleString, doublePattern);

        var doubleResult = match.Success ? double.Parse(match.Groups["integer"].Value) + (match.Groups["fraction"].Value == null ? 0 : double.Parse(match.Groups["fraction"].Value) / Math.Pow(10, match.Groups["fraction"].Value.Length)): 0;
        Console.WriteLine("Double of string '{0}' is {1}", sourceDoubleString, doubleResult);


#11 楼

我在此主题上的两分钱,试图提供一种通用的双重转换方法:

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
1,000,000,000
1.000.000.000
1,000,000,000.99
1.000.000.000,99
0.99,000,111,88
0,99.000.111.88

未实现默认转换,因此它将无法解析1.3,141,3.14或类似情况。

评论


原定为千的“ 1,000”将失败。

–Defkon1
19年10月2日在13:40

#12 楼

不必在所有解析中都指定语言环境,我更喜欢设置应用程序范围的语言环境,尽管如果字符串格式在整个应用程序中不一致,则此方法可能行不通。
br />在您的应用程序开始时对此进行定义,将使所有双重分析都期望逗号作为小数点分隔符。您可以设置适当的语言环境,以使小数和千位分隔符适合您要分析的字符串。

#13 楼

不指定要查找的小数点分隔符很难,但是如果您这样做,这就是我正在使用的格式:

    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", ',');
    }


这适用于任何区域性。与替换而不是swap的实现不同,它无法正确解析具有多个小数点分隔符的字符串。

#14 楼

我还改进了@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;
  }
}


#15 楼

这是一个解决方案,可以处理许多包含逗号和句点的数字字符串。该解决方案特别适用于金额,因此只能期望十分之几。
首先删除不是数字,逗号,句号或负号的任何内容。
string stringAmount = Regex.Replace(originalString, @"[^0-9\.\-,]", "");

然后将数字分成整数,然后十进制数字。
string[] decimalParsed = Regex.Split(stringAmount, @"(?:\.|,)(?=\d{2}$)");

(此Regex表达式选择从字符串末尾为两个数字的逗号或句点。)
现在,我们将整数除掉所有逗号,
string wholeAmount = decimalParsed[0].Replace(",", "").Replace(".", "");

if (wholeAmount.IsNullOrEmpty())
        wholeAmount = "0";

现在我们处理小数部分(如果有的话)。
string decimalAmount = "00";

if (decimalParsed.Length == 2)
    {
        decimalAmount = decimalParsed[1];
    }

最后,我们可以将整数和小数部分放在一起,并分析Double。
double amount = $"{wholeAmount}.{decimalAmount}".ToDouble();

这将处理200,00,1 000,00,1,000,1.000,33,2,000.000,78等。

#16 楼

System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CurrentCulture;

string _pos = dblstr.Replace(".",
    ci.NumberFormat.NumberDecimalSeparator).Replace(",",
        ci.NumberFormat.NumberDecimalSeparator);

double _dbl = double.Parse(_pos);


#17 楼

我认为这是最佳答案:

public static double StringToDouble(string toDouble)
{
    toDouble = toDouble.Replace(",", "."); //Replace every comma with dot

    //Count dots in toDouble, and if there is more than one dot, throw an exception.
    //Value such as "123.123.123" can't be converted to double
    int dotCount = 0;
    foreach (char c in toDouble) if (c == '.') dotCount++; //Increments dotCount for each dot in toDouble
    if (dotCount > 1) throw new Exception(); //If in toDouble is more than one dot, it means that toCount is not a double

    string left = toDouble.Split('.')[0]; //Everything before the dot
    string right = toDouble.Split('.')[1]; //Everything after the dot

    int iLeft = int.Parse(left); //Convert strings to ints
    int iRight = int.Parse(right);

    //We must use Math.Pow() instead of ^
    double d = iLeft + (iRight * Math.Pow(10, -(right.Length)));
    return d;
}


评论


解释您的代码并提供更多详细信息将很有帮助。

–查理·菲什(Charlie Fish)
16-09-26在20:24

这里要解释什么?一切都在评论中

–内啡肽
16-09-26在20:46

#18 楼

下面的效率较低,但是我使用了这种逻辑。仅当小数点后有两位数字时,此选项才有效。

double val;

if (temp.Text.Split('.').Length > 1)
{
    val = double.Parse(temp.Text.Split('.')[0]);

    if (temp.Text.Split('.')[1].Length == 1)
        val += (0.1 * double.Parse(temp.Text.Split('.')[1]));
    else
        val += (0.01 * double.Parse(temp.Text.Split('.')[1]));
}
else
    val = double.Parse(RR(temp.Text));


#19 楼

将数字相乘,然后除以之前的乘积。

例如,

perc = double.Parse("3.555)*1000;
result = perc/1000