Как правильно прочитать значение с плавающей запятой из файла XML независимо от региональных настроек?

Я читаю значение атрибута с плавающей запятой из узла в файле XML с помощью TXMLDocument:

<MyApp_Favorites version="1.0">

... с этим заявлением:

var
  ThisRootNode: IXMLNode;
  ThisVersion: Single;

// ...

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

Однако в моей системе немецкого языка я получаю это значение версии:

Эта версия = 10,00

...так как в моих региональных настройках запятая "," определяется как десятичный разделитель, а не точка "." как в файле XML. Но с региональной настройкой английского языка, где точка, скорее всего, определяется как настройка десятичного разделителя, результат будет правильным как «1.0».

Итак, как я могу убедиться, что независимо от региональных настроек значение чтения VALUE 1.0 всегда будет одинаковым? (Чтение значения версии как строки, а затем преобразование его в число с плавающей запятой не кажется очень элегантным методом).


person user1580348    schedule 19.12.2016    source источник
comment
Вот опять злостное минусование моих законных и хорошо сформулированных вопросов какими-то конкретными людьми без каких-либо объяснений!   -  person user1580348    schedule 20.12.2016


Ответы (3)


Число с плавающей запятой не является разумным форматом для номера версии, ошибки округления и отсутствие представления являются основными недостатками. Рассмотрите возможность использования записи с целыми числами для определения номеров версий.

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.
person J...    schedule 19.12.2016
comment
Спасибо @J..., но это всего лишь версия формата файла XML, поэтому она не так уж сложна. - person user1580348; 19.12.2016
comment
Не в смысле сложно. Но ваше решение очень элегантное и законченное. Спасибо! - person user1580348; 19.12.2016

Используйте строковое представление и выполните преобразование самостоятельно, используя TFormatSettings.Invariant:

ThisVersion := StrToFloat(ThisRootNode.Attributes['version'], TFormatSettings.Invariant);
person Uwe Raabe    schedule 19.12.2016

Это значение не следует рассматривать как значение с плавающей запятой. Вы открываете себя для проблем с представлением двоичных типов с плавающей запятой. Гораздо лучше прочитать строку и разобрать основные и второстепенные части, преобразовав их в целое число с помощью StrToInt. Разделите саму строку, используя Pos, чтобы найти расположение разделителя точек, или даже используя любую функцию Split.

С другой стороны, даже не ясно, нужно ли это значение в любом формате, кроме строки. Так зачем вообще делать что-либо, кроме чтения в виде строки?

Что касается фактического вопроса, который вы задали, если вы когда-нибудь захотите это сделать, используйте перегрузку StrToFloat, который принимает параметр TFormatSettings. И передайте настройки формата, которые устанавливают десятичный разделитель как '.'.

person David Heffernan    schedule 19.12.2016
comment
Ну, может быть, в будущем мне может понадобиться провести арифметическое сравнение двух или более значений версий. - person user1580348; 19.12.2016
comment
Не рассматривайте это как реальную ценность. Это не. Это два целых числа, мажорная и младшая версии. - person David Heffernan; 19.12.2016
comment
@ user1580348 Вы можете сделать это с помощью записи, используя перегрузку оператора - person J...; 19.12.2016
comment
Расширенная запись для тривиальной задачи, подобной этой, кажется чрезмерной. - person David Heffernan; 19.12.2016
comment
@DavidHeffernan, я полагаю, но это зависит от того, как часто он используется. Добавление оператора также тривиально, и вам больше никогда не придется беспокоиться об этой или подобных проблемах. - person J...; 19.12.2016