【问题标题】:Converting a string with commas to double and int are different. Why?将带逗号的字符串转换为 double 和 int 是不同的。为什么?
【发布时间】:2014-06-08 04:54:55
【问题描述】:

我正在从旧的 MFC GUI 迁移到 C#。

当我将字符串转换为整数类型时遇到意外异常,我正在构建基于表单的 GUI。我认为它与将字符串转换为双精度相同。

string str = "1,000";
double dthou = Convert.ToDouble(str);   // OK
int ithou = Convert.ToInt32(str);       // raises an exception

转换为 double 会给出正确的值:1000.0。 对于 int 转换,我能够得到一个解决方案:Convert.ToInt32() a string with Commas。

但我很好奇这背后是否有任何原因。 或者,我错过了什么?

我找到了一个类似但不完全重复的问题: Number parsing weirdness

在了解文化问题后[编辑]。

我处于一种文化冲击之中,因为直到现在,在韩国,浮点数和整数都用“,千位组和”表示。对于小数点(至少在现实世界中,在韩国,我的意思是,我认为......)。 我想我将不得不接受 MS Visual Studio 的当前设置并继续。

[EDIT2] 在解决这个问题之后。

我认为更多的是对格式化字符串的不一致处理。 ToDouble 接受带有千位分隔符的字符串(在我的文化中,逗号),但 ToInt32 不接受。如果ToDouble 是float | allowThousands,那么我要问的是为什么ToInt32 不能是integer | allowThousands。

【问题讨论】:

  • 你现在的文化是什么?
  • 这似乎是一个文化问题。
  • CultureInfo.CurrentCulture.Name 告诉我“ko-KR”
  • 在韩国,浮点数和整数都用“,”表示千位组和“.”。对于小数点这对于它的 .net 框架文化来说听起来很奇怪,因为它在 .net 世界中是相反的。
  • @Keugyeol 在您的[EDIT2] 部分之后更新了my answer..

标签: c# string int double


【解决方案1】:

在您的个人资料中,显示您来自韩国。这就是为什么我假设您当前的文化是ko-KR。 (还有你said。)

它是NumberDecimalSeparator 是. 但它是NumberGroupSeparator 是,

您的Convert.ToDouble 有效,它假定您的, 是千位分隔符,而不是十进制分隔符。这就是为什么你的dthou 将是1000 而不是1。

Convert.ToInt32(string) 显式使用Int32.Parse(string, CultureInfo.CurrentCulture),此方法implemented 喜欢;

public static int Parse(String s, IFormatProvider provider)
{
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
}

如您所见,此方法默认使用NumberStyles.Integer。这就是为什么您的字符串只能被其中之一成功解析的原因;

  • 领先的空白
  • 尾随空格
  • 前导符号(正面或负面)

并且由于您的字符串有千位分隔符或小数分隔符(这取决于您使用的是哪一个),因此此方法会引发异常。

除此之外,您可以使用 Int32.Parse(String, NumberStyles, IFormatProvider) overload,您可以指定您的 NumberStyles,例如 NumberStyles.AllowDecimalPoint 或 NumberStyles.AllowThousands

举个例子;

string str = "1,000";
int ithou = Int32.Parse(str, NumberStyles.AllowThousands,
                        new CultureInfo("ko-KR"));
Console.WriteLine(ithou); // Prints 1000

如果您想获得1 作为结果,您可以将CultureInfo.Clone method 用于您的文化并将其设置为NumberDecimalSeparator 和NumberGroupSeparator 等属性;

string str = "1,000";
CultureInfo c = (CultureInfo)CultureInfo.GetCultureInfo("ko-KR").Clone();
c.NumberFormat.NumberDecimalSeparator = ",";
c.NumberFormat.NumberGroupSeparator = ".";
int dthou = Int32.Parse(str, NumberStyles.AllowDecimalPoint, c);
Console.WriteLine(dthou ); // Prints 1

我不认为这是一个文化问题。这是不一致的处理 的格式化字符串。 ToDouble 接受带逗号的字符串,但是 ToInt32 没有。好像又回到了原来的问题, 但不能实现 ToInt32 来接受逗号,就像 ToDouble 函数?

亲爱的朋友,你还是想错了..

在您的情况下,一切都是文化问题。没有这样的东西“Convert.ToDouble() 接受带逗号的字符串,但 Convert.ToInt32() 不接受”。

让我们再来看看这些方法是如何实现的。

Convert.ToDouble(string) 明确使用Double.Parse(value, CultureInfo.CurrentCulture) 并且是implemented 喜欢;

public static double Parse(String s, IFormatProvider provider)
{
     return Parse(s, NumberStyles.Float| NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
}

有了这个NumberStyles.Float| NumberStyles.AllowThousands,您可以在代码中使用小数点或千位分隔符,但, 是您文化的NumberGroupSeparator 而不是NumberDecimalSeparator。这就是为什么您的字符串将被解析为数千个分隔符的原因。 没有这样的东西 Convert.ToDouble 使用带逗号的字符串。它可以使用您当前文化的NumberDecimalSeparator 或NumberGroupSeparator 取决于您的字符串具有哪个字符。如果两者相等,NumberDecimalSeparator 将占主导地位并被使用。

Convert.ToInt32(string) 明确使用Int32.Parse(string, CultureInfo.CurrentCulture) 并且它类似于implemented;

public static int Parse(String s, IFormatProvider provider)
{
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
}

正如我之前所说,NumberStyles.Integer 允许为您的字符串做三件事;前导空格、尾随空格和前导正号或负号。如果您的字符串有小数分隔符或千位分隔符,则无法解析无论是逗号还是点。

但不能实现 ToInt32 来接受逗号,就像 ToDouble 函数?

我之前告诉过你。 Convert.ToInt32 没有重载将 NumberStyles 作为参数。您可以使用 Int32.Parse(String, NumberStyles, IFormatProvider) overload 指定 NumberStyles 枚举来解析小数分隔符或千位分隔符。

【讨论】:

  • 感谢您的详细描述。在了解了 ToInt32() 的内部工作原理后,我想知道 ParseInt32 函数参数中是否可能是 NumberStyles.AllowThousands 而不是 NumberStyles.Integer。
  • @Keugyeol 更新了我的答案。看一眼。如果您使用NumberStyles.AllowThousands 而不改变您的文化,它会被解析为数千个分隔符,结果将是1000。如果您 Clone 您的文化并根据需要将其设置为 NumberDecimalSeparator 和 NumberGroupSeparator,则可以通过 NumberStyles.AllowDecimalPoint 枚举获得 1。
  • @Downvoter 至少愿意发表评论,这样我就可以知道我可能错在哪里?
【解决方案2】:

对于双重转换,有两种可能:

  1. 在您的文化中,, 是数字组分隔符。因此转换成功并返回值1000。
  2. 或者,在您的文化中,, 用作小数分隔符。再次成功转换为浮点数,但这次返回1。

对于转换为整数,"1,000" 根本不是整数。鉴于您的命名,我怀疑, 是您的数字组分隔符。而且您希望ToInt32() 以这种方式对待它。但是ToInt32() 不接受数字组分隔符。 ToInt32() 的有效字符是 0 到 9、- 或 + 的可选符号前缀以及前导或尾随空格。

【讨论】:

  • 在我的文化中“ko-KR”表示韩语,转换为 double 会给出正确的值,在本例中为 1000.0;
  • 这取决于你的意思是正确的。例如,在法国,正确答案是1.0。
  • 我已编辑评论以添加我的文化:“ko-KR”,谢谢。
  • 您可能需要考虑一下当您的代码在具有不同文化的机器上运行时会发生什么。
  • ToInt32() 的有效字符是 0 到 9 以及可选的 - 或 + 符号前缀 和前导或尾随空格。跨度>
【解决方案3】:

在英语文化中,小数点符号是“。” .在瑞典文化中,小数的叹息是“,”。万字可以是“”、“”、“.”。这就是为什么 C# 在小数点符号与其指定的文化不同时抛出异常的原因。

【讨论】:

  • 据我所知,在韩国,逗号用于浮点和整数表达式都是一样的,当其中一个转换引发异常时,我意外地被抓住了。
猜你喜欢
  • 1970-01-01
  • 2018-08-16
  • 2015-03-18
  • 2017-02-25
  • 2014-03-24
  • 2017-12-20
  • 2012-10-27
  • 1970-01-01
相关资源
最近更新 更多