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

时间:2014-12-12 12:13:16

标签: c#

我想将Text输入中的字符串解析为decimal。该值代表货币值。

目前我得到了这个解决方案:

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

4 个答案:

答案 0 :(得分:1)

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

  1. 从左到右扫描字符串
  2. 如果char ='。'然后dotFound = true; lastSeparatorPosition = index;点++
  3. 如果char =','然后commaFound = true; lastSeparatorPosition = index;逗号++
  4. 如果dot == 0&&逗号== 0然后是一个整数=>完成
  5. 如果点> 0&&逗号> 0然后lastSeparatorPosition上的那个是小数分隔符。从字符串=>中删除其他人完成
  6. / *只有一个分隔符类型* / if(点+逗号)> 1然后删除它们//因为必须是千位分隔符=>完成
  7. / *分隔符出现一次* /如果numberOfDigits右边的分隔符== 3那么你必须决定:-)整数或小数,分数为3位数
  8. 7是唯一一个像chiastic-security已经说过的问题。在这里,您只能考虑概念环境。所有其他情况都是安全的。

    玩得开心

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

123.456

123,456

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

答案 3 :(得分:0)

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

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

45,999.95

其中,是千分隔符和。是小数点分隔符

而在某些欧洲国家

45.999,95  

表示与上述相同但千位分隔符。并用作小数分隔符。

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

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

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

<强>更新

同样的情况是日期格式,例如在美国格式的月份是第一天然后是一天,而在澳大利亚的日子是第一个然后是月份,现在02/01/2015输入将意味着不同的系统不能告诉用户的意图。