Можно ли использовать DecimalSeparator, чтобы заставить функции Floattostr/Strtofloat использовать десятичную точку

В настоящее время я устанавливаю DecimalSeparator в '.' в каждой процедуре, которая использует эти функции.

Было бы намного проще установить это глобально в начале программы, но я обнаружил, что Delphi, похоже, периодически устанавливает это в текущую локаль.

Мне нужно убедиться, что десятичная точка используется для всех преобразований независимо от того, в какой стране используется программа, поскольку это стандарт для этого типа программы, а также структура всех файлов и протоколы связи, числовые отображения в формах/изменениях и т.д., должны быть отформатированы таким образом.

Мне сказали в другом потоке, что использование decimalseparator - это не правильный способ сделать это, но мне не дали альтернатив. Другие темы, касающиеся этого предмета, которые я прочитал, похоже, не предлагают каких-либо формативных указаний или слишком сложны.

Есть ли простой "правильный" способ сделать это?

Ответ 1

Я/был в предположении, что глобальная переменная DecimalSeperator не будет затронута RTL. Если нет, то все эти подпрограммы имеют необязательный параметр FormatSettings, который вы могли бы использовать. Globaly объявляет переменную TFormatSettings и использует ее для каждой из этих процедур.

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

Ответ 2

Да, глобальная переменная DecimalSeparator может быть изменена RTL во время выполнения, что вызвало много головной боли для меня несколько лет назад, прежде чем я понял это.

Дело в том, что DecimalSeparator обновляется RTL при изменении десятичного разделителя Windows, например, с помощью панели управления. Это может показаться довольно небольшой проблемой. В самом деле, как часто конечный пользователь меняет разделитель системных десятичных чисел?

Большая проблема заключается в том, что переменная DecimalSeparator обновляется (в соответствии с системными настройками) при каждом переключении пользователя (в Windows). Это стало для меня неожиданностью. То есть, если ваш системный параметр использует запятую (',') в качестве десятичного разделителя, и вы устанавливаете DecimalSeparator := '.' при запуске приложения, тогда DecimalSeparator вернется к запятой, если вы переключите пользователя (и вы заметите, что когда вы переключаетесь назад).

Вы можете сказать RTL не обновлять десятичный разделитель на

Application.UpdateFormatSettings := false;

Во всяком случае, существуют лучшие альтернативы DecimalSeparator, как обсуждалось в других ответах и ​​комментариях.

Ответ 3

Чтобы быть в безопасности, я использовал бы TFormatSettings, это имеет два преимущества:

  • Форматирование является потокобезопасным, другие коды/библиотеки не могут влиять на вашу функцию.
  • Вы не влияете на другой код, который, возможно, зависит от определенных параметров.

Здесь возможно выполнение:

function FloatToStrWithDecimalPoint(const Value: Extended; const Format: String = '0.###'): String;
var
  myFormatSettings: TFormatSettings;
begin
  GetLocaleFormatSettings(GetThreadLocale, myFormatSettings);
  myFormatSettings.DecimalSeparator := '.';
  Result := FormatFloat(Format, Value, myFormatSettings);
end;

Ответ 4

Вы можете исправлять каждую строку до и после вызова функции RTL с помощью некоторых функций ForceLocalSeparator() и ForceDotSeparator().

// before a RTL call
Function ForceLocalSeparator(Const StrValue: String): String;
Var
  SepPos: Integer;
Begin
  Result := StrValue;
  If DecimalSeparator <> '.' Then
    Begin
      SepPos := Pos( '.', Result );
      If SepPos > 0 Then Result[SepPos] := DecimalSeparator;
    End;
End;

// after a RTL call
Function ForceDotSeparator(Const StrValue: String): String;
Var
  SepPos: Integer;
Begin
  Result := StrValue;
  If DecimalSeparator <> '.' Then
    Begin
      SepPos := Pos( DecimalSeparator, Result );
      If SepPos > 0 Then Result[SepPos] := '.';
    End;
End;

Ответ 5

Хорошо, если у вас нет альтернативы. Предпочитают версии тех функций, которые принимают параметр TFormatSettings, если ваша версия Delphi достаточно недавняя, чтобы вы не мешали никакому другому коду, который полагается на эту глобальную переменную для поведения, зависящего от локали.

FloatToStr и StrToFloat являются языковыми функциями. Если вам нужно преобразовать значение с плавающей запятой в строку, чтобы сохранить ее где-нибудь, что программа будет читать позже (например, в файле, в реестре или в сетевом сокете), тогда вы должны использовать независимый от локали функции Str и Val для ваших преобразований. Они всегда используют . для десятичного разделителя, независимо от переменной DecimalSeparator или других параметров окружающей среды.