【问题标题】:How to read a floating point value correctly from an XML file independently from regional settings?如何独立于区域设置从 XML 文件中正确读取浮点值?
【发布时间】:2017-05-04 15:02:59
【问题描述】:

我正在使用TXMLDocument 从 XML 文件中的节点读取浮点属性值:

<MyApp_Favorites version="1.0">

...用这个声明:

var
  ThisRootNode: IXMLNode;
  ThisVersion: Single;

// ...

ThisVersion := ThisRootNode.Attributes['version'];
CodeSite.Send('ThisVersion', ThisVersion);

但是,在我的德语系统上,我得到了这个版本值:

此版本 = 10,00

...在我的区域设置中,逗号“,”被定义为小数分隔符,而不是点“。”就像在 XML 文件中一样。但是使用英语区域设置 - 点很可能被定义为小数分隔符设置 - 结果将正确为“1.0”。

那么,如何确保独立于区域设置的 1.0 读取值始终相同? (将版本值读取为字符串,然后将其转换为浮点数似乎不是一个非常优雅的方法。

【问题讨论】:

  • 在这里,我们再次遭到某些特定人员恶意否决我的合法和精心制定的问题而没有任何解释!

标签: xml delphi delphi-10.1-berlin regional-settings txmldocument


【解决方案1】:

浮点数不是版本号的明智格式,舍入错误和缺乏可表示性是主要缺点。考虑使用带有整数的记录来定义版本号。

program Project1;
{$APPTYPE CONSOLE}

uses
  SysUtils, StrUtils, Types;
type    
TVersion = record
  private
    procedure Set_AsString(AVersion : string);
    function Get_AsString: String;
  public
    Major: Integer;
    Minor: Integer;
    property AsString: String read Get_AsString write Set_AsString;
end;    

function TVersion.Get_AsString: String;
begin
  Result := Format('%d.%d', [Major, Minor]);
end;

procedure TVersion.Set_AsString(AVersion: string);
var
  split : TStringDynArray;
begin
  split := SplitString(AVersion, '.');
  Major := StrToInt(split[0]);
  Minor := StrToInt(split[1]);
end;

var
  v1, v2 : TVersion;
  s : string;
begin
  v1.Major := 12;
  v1.Minor := 34;
  WriteLn(v1.AsString);

  s := v1.AsString;
  v2.AsString := s;

  WriteLn(v2.AsString);
  ReadLn;
end.

【讨论】:

  • 谢谢@J...,但这只是 XML 文件格式的版本,因此没有那么复杂。
  • 没有难度。但是您的解决方案非常优雅和完整。谢谢!
【解决方案2】:

不应将此值视为浮点值。您对二进制浮点类型的表示问题敞开心扉。更好的是读取字符串并解析出主要和次要部分,使用StrToInt 将它们转换为整数。使用Pos 拆分字符串本身以查找句点分隔符的位置,或者实际上使用任何Split 函数。

另一方面,甚至不清楚您是否需要字符串以外的任何格式的此值。那么,除了将其作为字符串读取之外,为什么还要费心去做任何事情呢?

至于您提出的实际问题,您是否希望使用接受TFormatSettings 参数的StrToFloat 的重载。并传入将小数点分隔符设置为'.'的格式设置。

【讨论】:

  • 好吧,也许我将来需要对两个或多个版本值进行算术比较。
  • 不要将此视为真正的价值。它不是。它是两个整数,主要版本和次要版本。
  • @user1580348 您可以使用Operator Overloading 对记录执行此操作
  • 这样的琐碎任务的增强记录似乎超出了顶部。
  • @DavidHeffernan 我想,但这取决于它的使用频率。添加运算符也很简单,您再也不用担心这个或类似的问题了。
【解决方案3】:

使用字符串表示并使用TFormatSettings.Invariant自己进行转换:

ThisVersion := StrToFloat(ThisRootNode.Attributes['version'], TFormatSettings.Invariant);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多