首页 > 解决方案 > 从丢失小数位的 XML 中解析浮点值(C#)

问题描述

我在 C#(在 Unity 中,使用 VS2019)中有一个非常尴尬的行为,这让我疯狂了好几天,我真的很感谢你的帮助。

我有一个非常简单的 XML 文件,在这个简单的例子中只包含一个根节点和几个属性:

<?xml version="1.0" encoding="utf-8"?>
<root bit_depth="8" end_datetime="737061.75" start_datetime="737061">
</root>

我尝试阅读它:

    XmlDocument document = new XmlDocument();
    document.Load( _projectFilePath );
    XmlElement root = document.DocumentElement;

    System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo( "en-US" );

    string startTime = root.Attributes[ "start_datetime" ].Value;
    Debug.Log( "1st::: Read startTime number: " + startTime );
    double startTimeValue = double.Parse(startTime);
    Debug.Log( "2nd::: Parse startTime number: " + startTimeValue );

    string endTime = root.Attributes[ "end_datetime" ].Value;
    Debug.Log( "1st::: Read endTime number: " + endTime );
    double endTimeValue = double.Parse( endTime, CultureInfo.InvariantCulture );
    Debug.Log( "2nd::: Parse endTime number: " + endTimeValue );

结果如下:

1st::: Read startTime number: 737061
2nd::: Parse startTime number: 737061

1st::: Read endTime number: 7,370618E+07
2nd::: Parse endTime number: 73706180000000

只是……为什么?!?!?!?!当我显式解析双精度数时,为什么会将该浮点数弄乱为 7,370618E+07?

标签: c#xmlparsingunity3dxml-parsing

解决方案


在您的问题中,文本中的双精度数使用逗号小数分隔符:进行格式化7,370618E+07。这意味着您计算机上的当前语言环境Thread.CurrentCulture(由 表示)使用此分隔符。

但是,XML 文件中的数字使用句点小数分隔符:进行格式化737061.75double.Parse()将无法正确解析它们,因为输入字符串是使用为当前线程文化初始化的对象中的格式信息解释的。NumberFormatInfo通过将当前的 culure更改为new CultureInfo("de-DE").

由于 XML 文件通常使用不变的文化进行格式化,因此您应该使用不变的设置进行解析:

double startTimeValue = double.Parse(startTime, NumberFormatInfo.InvariantInfo);
double endTimeValue = double.Parse(endTime, NumberFormatInfo.InvariantInfo);

或者,使用System.Globalization.CultureInfo.InvariantCulture

double startTimeValue = double.Parse(startTime, System.Globalization.CultureInfo.InvariantCulture);
double endTimeValue = double.Parse(endTime,  System.Globalization.CultureInfo.InvariantCulture);

最好使用XmlConvert类中的实用程序:

double startTimeValue = XmlConvert.ToDouble(startTime);
double endTimeValue = XmlConvert.ToDouble(endTime);

此类提供用于在公共语言运行时类型和 XML 架构定义语言 (XSD) 类型之间进行转换的方法。转换数据类型时,返回的值与语言环境无关。 因此,它封装了有关用于格式化原始类型的 XML 约定的详细信息。

演示小提琴 #2 在此处显示上述修复。


作为另一个更简单的选择,尝试使用LINQ to XML 解析您的 XML

var doc = XDocument.Load(_projectFilePath);

var startTimeValue = (double)doc.Root.Attribute("start_datetime");
var endTimeValue = (double)doc.Root.Attribute("end_datetime");

LINQ to XMLXATtribute支持直接转换为doubledecimal消除对任何手动解析的需要。

演示小提琴#3在这里


最后,在您的代码中,您执行以下操作:

double endTimeValue = double.Parse(startTime);

我认为这是您问题中的错字,应该改为:

double endTimeValue = double.Parse(endTime);

推荐阅读