Можно ли использовать 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
или других параметров окружающей среды.