从指数表示法中解析数字

117

我需要将用指数表示法表示的字符串“1.2345E-02”(一个数字)解析为十进制数据类型,但是Decimal.Parse("1.2345E-02")会抛出错误。

10个回答

207

它是一个浮点数,你必须告诉它:

decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);

56

如果您指定NumberStyles.Float,它就能正常工作:

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Float);
Console.WriteLine(x); // Prints 0.012345

我并不确定为什么默认情况下不支持指数形式 - 默认情况下使用的是NumberStyles.Number,它使用了允许前导空格、允许尾随空格、允许前导符号、允许尾随符号、允许小数点和允许千位数分隔符等样式。可能这与性能有关;我想指定指数形式是相对较少的。


1
我正在尝试使用double使其正常工作,但似乎它不行。不确定为什么会这样..? - JanT
1
@JanT如果你能分享你的解决方法就太好了。我遇到了完全相同的问题,需要这个信息。谢谢! - Rick Glimmer
@RickGlimmer:我不确定你是如何知道你的问题与JanT的完全相同,因为他们从未提供他们试图做什么的详细信息。在我的代码中用double替换decimal对我来说很好用,就像我预期的那样。如果你能提供你正在尝试做什么、你正在使用的代码和结果的详细信息,那么帮助你将会更容易。 - Jon Skeet
@JonSkeet:“我想指定一个指数是相对罕见的。” 呵呵,呵呵。 我经常使用那些使用旧Fortran代码的系统输出的数据。 对我来说,这是正常情况。 - m_a_s
@m_a_s:是的,但你只是一个人。从我观察到的不仅是我的项目,还有我在各个地方看到的项目来看,我仍然认为这相对较少见。我相信绝大多数解析浮点数的代码都不需要处理指数。 - Jon Skeet
显示剩余7条评论

37

除了指定NumberStyles外,我建议您使用decimal.TryParse函数,例如:

decimal result;
if( !decimal.TryParse("1.2345E-02", NumberStyles.Any, CultureInfo.InvariantCulture, out result) )
{
     // do something in case it fails?
}

如果你确定格式的话,可以使用特定的集合来代替NumberStyles.Any。例如:

NumberStyles.AllowExponent | NumberStyles.Float

1
但是如果使用AllowExponent,使用Float并不是必需的,因为Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent。 - Lukáš Kmoch
@LukášKmoch 您说得对。这是习惯使然,因为其他人(除了 Any)不包括它。执行额外的 OR 应该不会有影响。 - Sverrir Sigmundarson

15
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);

13

对所选答案要谨慎:在Decimal.Parse中有一个微妙之处,指定了System.Globalization.NumberStyles.Float,这可能会导致System.FormatException,因为您的系统可能正在等待用“,”而不是“.”格式化的数字。

例如,在法国的表示法中,“1.2345E-02”是无效的,您必须首先将其转换为“1,2345E-02”。

总之,请使用以下类似内容:

Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);

2
你说得完全正确。我不明白为什么没有其他人提出这个问题。 - Neithan Max
14
最好在Parse方法的第三个参数中使用CultureInfo.InvariantCulture。 - Andriy Kozachuk

10

在使用 decimal.Parse(String) 方法时,其默认的 NumberStyleNumberStyles.Number,所以如果你只想添加允许指数的功能,那么可以使用位运算符 OR 来包含 NumberStyles.AllowExponent

decimal d = decimal
    .Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);

5
我发现在某些情况下,传入NumberStyles.Float会改变字符串处理的规则,并导致与NumberStyles.Number(由decimal.Parse使用的默认规则)不同的输出结果。
例如,在我的计算机上,以下代码将生成一个FormatException
CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5", NumberStyles.Float, culture); // FormatException thrown here

我建议使用输入 NumberStyles.Number | NumberStyles.AllowExponent,因为这样可以允许指数形式的数字,并且仍然可以按照 decimal 规则处理字符串。
CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5",NumberStyles.Number | NumberStyles.AllowExponent, culture); // Does not generate a FormatException

回答发帖者的问题,正确的答案应该是:

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Console.WriteLine(x);

2

关于使用NumberStyles.Any的警告:

"6.33E+03"按预期转换为6330。在德国,小数点用逗号表示,但是6,33E+03转换为633000!这对我的客户是一个问题,因为生成数据的文化并不知道,可能与操作数据的文化不同。在我的情况下,我总是有科学计数法,所以我可以在解析之前始终将逗号替换为小数点,但是如果您正在处理任意数字,例如格式漂亮的数字,如1,234,567,则该方法无效。


0

您不需要替换点(或逗号),只需指定输入的 IFormatProvider:

float d = Single.Parse("1.27315", System.Globalization.NumberStyles.Float, new CultureInfo("en-US"));
float d = Single.Parse("1,27315", System.Globalization.NumberStyles.Float, new CultureInfo("de-DE"));

0
如果您想检查和转换指数值,请使用此功能。
string val = "1.2345E-02";
double dummy;
bool hasExponential = (val.Contains("E") || val.Contains("e")) && double.TryParse(val, out dummy);
if (hasExponential)
{
    decimal d = decimal.Parse(val, NumberStyles.Float);
}

希望这能帮助到某个人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接