Как конвертировать float или валюту в локализованную строку?

В Delphi1, используя FloatToStrF или CurrToStrF, для представления десятичной метки будет автоматически использован символ DecimalSeparator. К сожалению DecimalSeparator объявлен в SysUtils как Char1,2:

var 
  DecimalSeparator: Char;

В то время как LOCALE_SDECIMAL разрешается использовать до трех символов:

Символ(ы), используемые для десятичного разделителя, например, "..." в "3.14" или "..." в "3,14". Максимальное количество символов, допустимое для этой строки - четыре, включая завершающий нулевой символ.

Это приводит к тому, что Delphi не может корректно прочитать десятичный разделитель; возвращаясь к предположению о десятичном разделителе по умолчанию ". ":

DecimalSeparator := GetLocaleChar(DefaultLCID, LOCALE_SDECIMAL, '.');

На моем компьютере, , который является символом , это приводит к неправильной локализации значений с плавающей точкой и валюты с десятичной отметкой U+002E (полная остановка).

i am желающие напрямую вызывать функции Windows API, которые предназначены для преобразования значений с плавающей точкой, или валюты, в локализованную строку:

Кроме этих функций принимают строку из графических кодов, где разрешены только символы:

  • Символы "от 0" до "9" (U+0030. . U+0039)
  • Одна десятичная точка (). ) если число является значением с плавающей точкой (U+002E)
  • Знак минуса в позиции первого символа, если число является отрицательным значением (U+002D)

Что было бы хорошим способом1 конвертировать значение с плавающей точкой, или валюту, в строку, которая подчиняется этим правилам? например,

  • 1234567.893332
  • -1234567

, учитывая, что локаль локального пользователя (т.е. моего компьютера):


Ужасный, ужасный, хакерский, который я мог бы использовать:

function FloatToLocaleIndependantString(const v: Extended): string;
var
   oldDecimalSeparator: Char;
begin
   oldDecimalSeparator := SysUtils.DecimalSeparator;
   SysUtils.DecimalSeparator := '.'; //Windows formatting functions assume single decimal point
   try
      Result := FloatToStrF(Value, ffFixed, 
            18, //Precision: "should be 18 or less for values of type Extended"
            9 //Scale 0..18.   Sure...9 digits before decimal mark, 9 digits after. Why not
      );
   finally
      SysUtils.DecimalSeparator := oldDecimalSeparator;
   end;
end;

Дополнительная информация о цепочке функций, которые VCL использует:

Note

1 в моей версии Delphi
2 и в текущих версиях Delphi

15
задан Community 8 October 2014 в 17:07
поделиться