繁体   English   中英

从 XML 解析浮点值丢失小数位(C#)

[英]Parsing floating value from XML losing decimal places (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?

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

但是,XML 文件中的数字使用句点小数分隔符进行格式化: 737061.75 double.Parse()将无法正确解析它们,因为使用为当前线程区域性初始化的NumberFormatInfo object 中的格式信息解释输入字符串。 通过将当前的文化更改为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 class 中的实用程序:

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

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

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


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

var doc = XDocument.Load(_projectFilePath);

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

LINQ 到 XML 的XATtribute支持直接转换为double精度或decimal ,无需任何手动解析。

演示小提琴#3在这里


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

double endTimeValue = double.Parse(startTime);

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

double endTimeValue = double.Parse(endTime);

我在 Visual Studio 和 dotnetfiddle 中运行了您的代码,得到了以下结果。

        XmlDocument document = new XmlDocument();
        document.LoadXml("<root bit_depth=\"8\" end_datetime=\"737061.75\" start_datetime=\"737061\"></root >");

        string startTime = document.ChildNodes[0].Attributes["start_datetime"].Value;
        Console.WriteLine("1st::: Read startTime number: " + startTime);
        double startTimeValue = double.Parse(startTime);
        Console.WriteLine("2nd::: Parse startTime number: " + startTimeValue);

        string endTime = document.ChildNodes[0].Attributes["end_datetime"].Value;
        Console.WriteLine("1st::: Read endTime number: " + endTime);
        double endTimeValue = double.Parse(startTime);
        Console.WriteLine("2nd::: Parse endTime number: " + endTimeValue);

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

我建议您检查文件的编码并使用相同的编码读取它。 并检查计算机上安装的本地化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM