如何parsing一个小数点的string为一个双?

我想parsing一个string像"3.5"到一个double。 然而,

 double.Parse("3.5") 

收益35和

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

抛出一个FormatException

现在我的电脑的语言环境设置为德语,其中逗号用作小数点分隔符。 它可能需要做些什么和double.Parse()期待"3,5"作为input,但我不知道。

我怎样才能parsing一个string包含一个十进制数字,可能或不可能是我的当前区域设置中指定的格式?

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

我通常使用多文化function来parsing用户input,主要是因为如果有人习惯了数字键盘,并使用逗号作为小数点分隔符的文化,那么这个人将使用数字键盘的点而不是逗号。

 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评论是真实的。 为了防御,我在一个受控的环境中使用这个function,我知道这个文化可以是en-US,en-CA或fr-CA。 我使用这个函数,因为在法文中,我们使用逗号作为小数点分隔符,但任何在财务工作的人都会使用小数点位置上的小数点分隔符,但这是一个点,而不是逗号。 所以即使在fr-CA文化中,我也需要parsing出一个小数点分隔的数字。

诀窍是使用不变的文化,parsing所有文化中的点。

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

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

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

我在我的电脑上testing了两个:

 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; } 
 Double.Parse("3,5".Replace(',', '.'), CultureInfo.InvariantCulture) 

在parsing之前用逗号replace逗号。 用逗号作为小数点分隔符的国家很有用。 考虑限制用户input(如有必要)为一个逗号或点。

看,上面提到的每个答案都是用一个常量string来替代string,只能是错误的。 为什么? 因为你不尊重Windows的区域设置! Windows确保用户可以自由设置他/她想要的任何分隔符。 他/她可以打开控制面板,进入区域面板,点击高级,随时更改angular色。 即使在你的程序运行。 想想这个。 一个好的解决scheme必须意识到这一点。

所以,首先你要问自己,这个数字是从哪里来的,你想要parsing的。 如果它来自.NET Framework中的input没有问题,因为它将采用相同的格式。 但也许它来自外部,也许来自外部服务器,也许来自只支持string属性的旧数据库。 在那里,数据库pipe理员应该已经规定了数字要存储的格式。 如果你知道,例如它将是一个美国的数据库与美国格式,你可以使用这段代码:

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

这在世界上任何地方都能正常工作。 请不要使用“Convert.ToXxxx”。 “转换”类只被认为是任何方向转换的基础。 除此之外:您也可以使用类似的DateTimes机制。

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

以下代码在任何情况下都能完成这项工作。 这是一个有点parsing。

 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%正确的转换是不可能的,如果价值来自用户input。 例如,如果值是123.456,则可以是分组,也可以是小数点。 如果你真的需要100%,你必须描述你的格式,如果不正确,则抛出exception。

但是我改进了JanW的代码,所以我们提前一点点到100%。 后面的想法是,如果最后一个分隔符是一个groupSeperator,这将是一个整数types,比双。

添加的代码是GetDouble中的第一个。

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

不必在所有分析中指定区域设置,我倾向于设置应用程序范围的区域设置,但如果string格式在应用程序中不一致,则可能无法使用。

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

在应用程序开始时定义这个函数会使得所有的双parsing都需要逗号作为小数分隔符。 您可以设置适当的区域设置,以便小数点和千位分隔符适合要分析的string。

没有指定要查找的小数点分隔符是很困难的,但是如果你这样做,这就是我正在使用的:

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

这应该适用于任何文化。 它正确地parsing了具有多个小数分隔符的string,不像取代swap的实现那样。

我改进了@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; } } 
 System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CurrentCulture; string _pos = dblstr.Replace(".", ci.NumberFormat.NumberDecimalSeparator).Replace(",", ci.NumberFormat.NumberDecimalSeparator); double _dbl = double.Parse(_pos); 

乘以数字,然后再除以之前乘以的数字。

例如,

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

我认为这是最好的答案:

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

下面效率较低,但我使用这个逻辑。 只有在小数点后有两位数字时才有效。

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