x.xxxx недопустимо с плавающей запятой. Преобразование между языками / локальными точками

#delphi #floating-point

#строка #delphi #значение с плавающей запятой

Вопрос:

У меня есть испанский пользователь, который получает invalid floating point error при выполнении этого

 var
  S : String;
  R : Real;
begin
  S := '3.12345';
  R := StrToFloat(S); //- Exception here.
  

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

Комментарии:

1. Знаете ли вы (то есть на момент запуска программы) национальные настройки, используемые в строке?

2. Да, я делаю (причина, по которой это строка, заключается в том, что это ответ API).

Ответ №1:

Создайте свою собственную версию StrToFloat

 function StrToFloat_UK(const AStr: string): Float;
var
  FS: TFormatSettings;
begin
  FS.Create('en-UK');
  Result:= StrToFloat(AStr, FS): 
end;
  

И используйте это вместо StrToFloat .

Комментарии:

1. Теперь я абсолютно не представляю, что вы делаете. TFormatSettings это запись, вы это знаете, верно?

2. Из документации embarcadero: 1. Объявите переменную типа TFormatSettings. 2. Вызовите TFormatSettings. Создайте, чтобы заполнить переменную TFormatSettings информацией о локали. 3. Передайте переменную TFormatSettings в качестве последнего параметра процедуры форматирования строки.

3. Ну, у меня это не компилируется. И с каких пор вам нужна Free запись?! Возможно, вы используете более новую версию Delphi. В Delphi 2009 приведенный выше код является бессмыслицей…

4. Хорошо, теперь я вижу, что эта запись изменилась со времен Delphi 2009. Delphi 2009 , Delphi XE Но, конечно, вы не должны Free использовать это даже в Delphi XE!

Ответ №2:

Используйте вторую перегрузку StrToFloat с TFormatSettings , для DecimalSeparator которой . установлено значение, равное.

Комментарии:

1. Я выбрал другой вместо вашего из-за исходного кода, но оба они почти одинаковы. Спасибо за ответ!

2. @Wizzard: Все в порядке. В любом случае я не мог понять, как инициализировать TFormatSettings . Прошло несколько лет с тех пор, как я работал с Object Pascal, и мне никогда не приходилось сталкиваться с этим; этот ответ был в основном результатом быстрого поиска в Интернете (и я был совершенно уверен, что каждая функция синтаксического анализа, чувствительная к локали, должна иметь возможность заранее настроить язык для использования).

Ответ №3:

Вы могли бы использовать процедуру val , она игнорирует настройки локальной системы.

 var
S : String;
R : Real;
Test: Integer;
begin
  S := '3.12345';
  Val(S, R, Test);
end;
  

Комментарии:

1. Классный трюк. Но я надеюсь, что значение Val не ограничено только реальным типом и отлично работает с Double . Надеюсь, есть перегрузки для double?

2. Также работает с удвоениями и целыми числами. Само по себе оно не перегружено, это магия компилятора.

Ответ №4:

Если вы знаете, что строки используют . в качестве десятичного разделителя, то вам следует сделать что-то вроде

 procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.UpdateFormatSettings := false;
  DecimalSeparator := '.';
end;
  

Строка

 Application.UpdateFormatSettings := false;
  

очень важно. Значение по умолчанию этого свойства равно true , и в таком случае DecimalSeparator переменная может быть возвращена к своему значению по умолчанию (например, , ) в любое время, например, при смене пользователя.

Комментарии:

1. Избегайте использования глобального DecimalSeparator для этого, так как вы не будете знать, какие другие единицы зависят от этого (и которые сломаются). Лучше использовать локальный TFormatSettings экземпляр.

2. -1: Игнорировать пользовательские настройки для всего в вашем приложении — это неправильный путь, особенно когда вы можете использовать перегруженную версию, о чем сообщают Джоуи и Йохан.