使用任何小数分隔符将字符串解析为十进制

我想解析从Text输入到十进制的字符串。 该值表示货币值。

目前我有这个解决方案:

private Decimal CastToDecimal(string value) { Decimal result; var valid = Decimal.TryParse(value, NumberStyles.Currency, null, out result); return valid ? result : -1; } 

到目前为止,这种方法效果很好,除了可能的文化差异。 我是德国人,我希望大多数用户进入德国风格的标点。 但有可能有人使用“。” 而不是“,”,转换将失败。

“123,45€”=> 123.45

“123.456,78€”=> 123456.78

“123.45€”=> 12345 < – 我希望结果在这里是123.45

有没有办法自动检测使用的文化的十进制值? 如果您使用德语或英语标点符号无关紧要,您仍会得到相同的结果吗?

更新:

感谢您的帮助,我创建了一种方法,可以满足我的需求(我认为)。

 private static Decimal CastToDecimal(string value) { Decimal resultDe; Decimal resultEn; var style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands; var cultureDe = CultureInfo.CreateSpecificCulture("de-DE"); var cultureEn = CultureInfo.CreateSpecificCulture("en-GB"); var deValid = Decimal.TryParse(value, style, cultureDe, out resultDe); var enValid = Decimal.TryParse(value, style, cultureEn, out resultEn); var minVal = Math.Min(resultDe, resultEn); var maxVal = Math.Max(resultDe, resultEn); if (!deValid) return resultEn; if (!enValid) return resultDe; return BitConverter.GetBytes(decimal.GetBits(minVal)[3])[2] > 2 ? maxVal : minVal; } 

这段代码……

  Console.WriteLine(CastToDecimal("123,45")); Console.WriteLine(CastToDecimal("123.45")); Console.WriteLine(CastToDecimal("123,450")); Console.WriteLine(CastToDecimal("123.450")); Console.WriteLine(CastToDecimal("123.123,45")); Console.WriteLine(CastToDecimal("123,123.45")); 

返回:

 123,45 123,45 123450 123450 123123,45 123123,45 

http://msdn.microsoft.com/en-us/library/3s27fasw%28v=vs.110%29.aspx中包含设置NumberStyle的解决方案可能会有所帮助。

 ... value = "1.345,978"; style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands; culture = CultureInfo.CreateSpecificCulture("es-ES"); if (Double.TryParse(value, style, culture, out number)) Console.WriteLine("Converted '{0}' to {1}.", value, number); else Console.WriteLine("Unable to convert '{0}'.", value); // Displays: // Converted '1.345,978' to 1345.978. value = "1 345,978"; if (Double.TryParse(value, style, culture, out number)) Console.WriteLine("Converted '{0}' to {1}.", value, number); else Console.WriteLine("Unable to convert '{0}'.", value); ... 

我前段时间遇到过同样的问题。 我的解决方案是用Java编写自己的解析器。 该算法首先清理字符串。 简要说明如下:

  1. 从左到右扫描字符串
  2. 如果char =’。’ 然后dotFound = true; lastSeparatorPosition = index; 点++
  3. 如果char =’,’那么commaFound = true; lastSeparatorPosition = index; 逗号++
  4. 如果dots == 0 && commas == 0则其整数=>完成
  5. 如果点> 0 &&逗号> 0,那么lastSeparatorPosition中的那个是小数分隔符。 从字符串=>完成中删除其他人
  6. / *只有一个分隔符类型* / if(点+逗号)> 1然后删除它们//因为必须是千位分隔符=>完成
  7. / *分隔符出现一次* /如果numberOfDigits右边的分隔符== 3那么你必须决定:-)整数或小数,3位数的分数

7是唯一一个像chiastic-security已经说过的问题。 在这里,您只能考虑概念环境。 所有其他情况都是安全的。

玩得开心

这是不可能的,因为有两种不同文化中有意义的字符串,但意味着不同的东西。 例如:

 123.456 123,456 

第一个在英国有123个,但在德国有123456个; 第二个是英国的123456,但在法国略高于123。

唯一的解决方案是在输入上添加validation,如果它是一个网页,则为用户提供示例,然后根据用户的文化找到获取输入的方法。 我建议你不要尝试做你正在尝试的事情,因为有些文化与货币相互矛盾;

美国/澳大利亚/许多其他人使用以下格式

 45,999.95 

在哪里,是千分隔符和。 是小数点分隔符

而在一些欧洲国家

 45.999,95 

意思是与上面相同但千位分隔符。 并用作小数分隔符。

现在问题是无法保证用户同时使用两个分隔符,您的系统可能会假设千位分隔符为十进制,依此类推。

如果您真的不想打扰用户,请为主要货币和次要货币创建单独的输入字段。

所以最好不去那里。 我相信这可能会有所帮助。 快乐编码:)

更新

同样的情况是日期格式,例如以美国格式月份首先出现,然后是一天,而在澳大利亚日出现第一个月然后现在是2015年1月2日输入将意味着不同的系统无法说明用户的意图。