C# 如何将小数点为双精度的字符串解析为双精度?

C# 如何将小数点为双精度的字符串解析为双精度?,c#,string,parsing,double,C#,String,Parsing,Double,我想将3.5这样的字符串解析为双精度。但是, double.Parse("3.5") 收益率35和 double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint) 引发格式化异常 现在,我的计算机的语言环境设置为德语,其中逗号用作十进制分隔符。它可能需要做些什么,然后double.Parse需要3,5作为输入,但我不确定 如何解析包含十进制数的字符串,该十进制数的格式可能与当前区域设置中指定的格式相同,也可

我想将3.5这样的字符串解析为双精度。但是,

double.Parse("3.5") 
收益率35和

double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint) 
引发格式化异常

现在,我的计算机的语言环境设置为德语,其中逗号用作十进制分隔符。它可能需要做些什么,然后double.Parse需要3,5作为输入,但我不确定


如何解析包含十进制数的字符串,该十进制数的格式可能与当前区域设置中指定的格式相同,也可能与当前区域设置中指定的格式不同?

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

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

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

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。我使用此函数是因为在法语中,我们使用逗号作为小数分隔符,但在金融行业工作过的任何人都会在numpad上始终使用小数分隔符,但这是一个点,而不是逗号。所以,即使在fr CA文化中,我也需要解析将有一个点作为小数分隔符的数字

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

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

以下代码在任何情况下都可以完成此任务。这是一个有点解析

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

我认为如果值来自用户输入,100%正确的转换是不可能的。e、 g.如果值为123.456,则可以是分组,也可以是小数点。如果您真的需要100%,您必须描述您的格式,如果格式不正确,则抛出异常

但是我改进了JanW的代码,所以我们在100%的情况下取得了一些进步。背后的想法是,如果最后一个分隔符是groupseparator,那么这将是一个整数类型,而不是double类型

添加的代码位于GetDouble的第一个if中


我还改进了@JanW的代码

我需要它来格式化来自医疗器械的结果,它们还发送>1000、23.3e02、350E-02和负片

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

我不必在所有解析中指定区域设置,而是更喜欢设置应用程序范围的区域设置,尽管如果应用程序中的字符串格式不一致,这可能不起作用

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

在应用程序开始时定义它将使所有的双解析都使用逗号作为十进制分隔符。您可以设置适当的区域设置,以便十进制和千位分隔符适合您正在分析的字符串。

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

所以,首先你必须问自己,这个数字来自哪里,你想解析它。如果它来自.NET Framework中的输入,则没有问题,因为它将采用相同的格式。但它可能来自外部,可能来自外部服务器,可能来自只支持字符串属性的旧数据库。在这里,db管理员应该给出一个存储数字的格式规则。例如,如果您知道它将是US格式的US DB,您可以使用以下代码:

CultureInfo usCulture = new CultureInfo("en-US");
NumberFormatInfo dbNumberFormat = usCulture.NumberFormat;
decimal number = decimal.Parse(db.numberString, dbNumberFormat);

这在世界上任何地方都能很好地发挥作用。请不要使用“Convert.toxxx”。“Convert”类仅被视为任何方向转换的基础。此外:您也可以对日期时间使用类似的机制。

如果不指定要查找的小数点分隔符,这是很困难的,但如果您这样做,我将使用以下方法:

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

这应该适用于任何文化。它无法正确解析具有多个十进制分隔符的字符串,这与替换而不是交换的实现不同。

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

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

把这个数字相乘,然后除以你之前乘以的数

比如说,

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

我不能写评论,所以我写在这里:

double.Parse3.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
这是Pierre Alain Vigeant提到的正确方法

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

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

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 5,000,111.3 5.000.111,3 0.99,000,111,88 0,99.000.111.88 没有德福
lt转换已实现,因此尝试解析1.3、14、1、3.14或类似情况时将失败。

这里有一个解决方案,可以处理任何包含逗号和句点的数字字符串。此解决方案特别适用于货币数量,因此只需要第十分之一和第一百位。任何更多的都被视为一个整数

首先删除任何不是数字、逗号、句点或负号的内容

string stringAmount = Regex.Replace(originalString, @"[^0-9\.\-,]", "");
然后我们把数字分成整数和小数

string[] decimalParsed = Regex.Split(stringAmount, @"(?:\.|,)(?=\d{2}$)");
此正则表达式选择一个逗号或句点,该逗号或句点是字符串末尾的两个数字

现在我们取整数,去掉任何逗号和句点

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,1000,1.000,33,2000.000,78等。十进制逗号肯定会影响输出。如果适合您的情况,请不要忘记double.TryParse方法。我喜欢使用XmlConvert类。。。您知道这比使用CultureInfo.InvariantCulture更好、更差和/或不同吗?XmlConvert并不是真正用来解析代码中的一个双精度值。我更喜欢使用double.Parse或Convert.ToDouble,这使我的意图变得明显。这意味着double.Parse使用默认区域性,它可能不包含点作为小数点??如果转换12345678.12345678,它也会转换12345678.123457对我不起作用:跳过逗号并返回和int作为double我不确定这是个好主意。如果不了解区域性,就无法可靠地解析double:在德国,double值可能包含“.”,但在那里它们被认为是数千个分隔符。因此,在Legate的例子中,GetDouble3.5在德国地区返回35,在美国环境返回3.5。不,Pierre Alain是对的,正如它所写的那样。如果你的文化说圆点是千分之一,那么3.5被视为35,这是好的。但是,如果您将区域性作为点的无规则,则字符将被解析为小数点,并且它也可以工作。我本来可以避免尝试enUS区域性,但这是个人的选择。如果在区域性中使用numpad和逗号,则点键将设置为逗号。numpad十进制分隔符取决于键盘布局,而不是区域设置-至少在Windows 7上,我使用匈牙利语编写文本、电子邮件。。。我们需要编写代码,所以它可以是点或逗号。我还使用自定义的区域设置,将十进制分隔符从“,”更改为“.”,将列表分隔符从“;”更改为“;”到“,”。你知道,因为。。。祝我们所有人在编写多元文化应用程序时好运;如果系统区域性使用逗号作为分隔符,则此代码不适用于100.35这样的数字。你可能希望它返回大约100个数字,但它返回10035.1.234.567.890将返回1234567.890我还没有尝试过,但是如果你在不同的文化中执行应用程序,我认为这段代码不会成功,我认为:/比获得+133票的答案正确得多。。。它允许使用或在两个系统上同时运行。小数点分隔符…@Badiboy你能解释一下这个答案的错误吗?据我所知,不变量文化总是以“.”作为十进制分隔符。因此,它应该适用于两种系统。@Alexal11223您是对的。这就是为什么我说这个答案比更流行的更好。PS:友好地说,如果您有,as列表分隔符,即1234560.01,此代码也将失败,但我根本不知道如何解决此问题:这不是一个好的答案,因为在某些文化信息中,是千位分隔符,可以使用。如果将其替换为一个点,则最终会有几个点,解析将失败:Double.Parse12345.67.toString,new CultureInfo.replace',',',',CultureInfo.InvariantCulture,因为12345.67.toString,new CultureInfo.replace',','。将被格式化为12.345.671234.56->1.234.56而不是解析器。另一个方法是检查数字是否包含“.”和“,”并用空字符串替换“,”,如果只有“,”逗号,则将其替换为“.”同意!尝试手动实现区域性功能最终会导致一个您意想不到的情况,并且会让您头痛不已。让.NET妥善处理。一个大问题是,当用户使用的十进制分隔符在其文化设置中不被视为十进制分隔符时:……因为在加拿大,我们写的是3,5而不是3.5。你确定吗?根据:国家里有一个点。用作小数点的符号包括。。。加拿大使用英语时。这不是更多关于使用法语版本的Windows吗?因为法语版本。在蒙特利尔,我们写的是3,5,而不是3.5,所以根据你的逻辑,总是只有1个返回true?看,仍然有一个错误。对于输入字符串,如GetDouble10,,,,,,,,0,0.0。上述函数返回100.1000,因为1000将失败。不工作,以3,5失败
string[] decimalParsed = Regex.Split(stringAmount, @"(?:\.|,)(?=\d{2}$)");
string wholeAmount = decimalParsed[0].Replace(",", "").Replace(".", "");

if (wholeAmount.IsNullOrEmpty())
        wholeAmount = "0";
string decimalAmount = "00";

if (decimalParsed.Length == 2)
    {
        decimalAmount = decimalParsed[1];
    }
double amount = $"{wholeAmount}.{decimalAmount}".ToDouble();