15

Delphi 1では、FloatToStrFまたはを使用すると、小数点を表すCurrToStrFために文字が自動的に使用されます。DecimalSeparator残念ながらDecimalSeparator 、SysUtilsではChar1,2として宣言されています:

var 
  DecimalSeparator: Char;

最大3文字までLOCALE_SDECIMAL使用できます。

小数点に使用される文字(「。」など)。「3.14」または「、」の「3,14」。この文字列に許可される最大文字数は、終了ヌル文字を含めて4文字です。

これにより、Delphiは小数点の読み取りに失敗します。""のデフォルトの小数点を想定するためにフォールバックします.

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

私のコンピューターでは、かなりの文字ですが、これにより、浮動小数点と通貨の値がU + 002E(終止符)の小数点で誤ってローカライズされます。

浮動小数点または通貨の値をローカライズされた文字列に変換するように設計されたWindowsAPI関数を直接呼び出します

これらの関数を除いて、画像コードの文字列を取ります。許可される文字は次のとおりです。

  • 文字「0」から「9」(U+0030.. U+0039
  • .数値が浮動小数点値の場合は小数点1桁( 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が使用する一連の機能に関する追加情報:

ノート

私のバージョンのDelphi2
現在のバージョンのDelphiでは1

4

2 に答える 2

2

わかりました、これはあなたが望むものではないかもしれませんが、D2007以降で動作します。スレッドセーフですべて。

uses Windows,SysUtils;

var
  myGlobalFormatSettings : TFormatSettings;

// Initialize special format settings record
GetLocaleFormatSettings( 0,myGlobalFormatSettings);
myGlobalFormatSettings.DecimalSeparator := '.';


function FloatToLocaleIndependantString(const value: Extended): string;
begin
  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
        myGlobalFormatSettings
  );
end;
于 2011-08-16T22:24:55.183 に答える
2

FloatToDecimalDelphiは、浮動小数点(例Extended)とCurrency値をさらにフォーマットするための便利な構造に変換するというプロシージャを提供します。例えば:

FloatToDecimal(..., 1234567890.1234, ...);

あなたにあげる:

TFloatRec
   Digits: array[0..20] of Char = "12345678901234"
   Exponent: SmallInt =           10
   IsNegative: Boolean =          True

ここExponentで、小数点の左側の桁数を示します。

処理する必要のある特殊なケースがいくつかあります。

  • 指数はゼロです

       Digits: array[0..20] of Char = "12345678901234"
       Exponent: SmallInt =           0
       IsNegative: Boolean =          True
    

    小数点の左側に数字がないことを意味します。例:.12345678901234

  • 指数が負です

       Digits: array[0..20] of Char = "12345678901234"
       Exponent: SmallInt =           -3
       IsNegative: Boolean =          True
    

    小数点と最初の桁の間にゼロを配置する必要があることを意味します。例:.00012345678901234

  • 指数は-32768NaN、数値ではありません)

       Digits: array[0..20] of Char = ""
       Exponent: SmallInt =           -32768
       IsNegative: Boolean =          False
    

    値が数値ではないことを意味します。例:NAN

  • 指数は32767INF、または-INF)です

       Digits: array[0..20] of Char = ""
       Exponent: SmallInt =           32767
       IsNegative: Boolean =          False
    

    値が正または負の無限大(IsNegative値に応じて)であることを意味します。例:-INF


FloatToDecimalロケールに依存しない「画像コード」の文字列を作成するための開始点として使用できます。

次に、この文字列を適切なWindowsGetNumberFormatまたはGetCurrencyFormat関数に渡して、実際の正しいローカリゼーションを実行できます。

私は自分CurrToDecimalStringで書いたFloatToDecimalStringもので、数値を必要なロケールに依存しない形式に変換します。

class function TGlobalization.CurrToDecimalString(const Value: Currency): string;
var
    digits: string;
    s: string;
    floatRec: TFloatRec;
begin
    FloatToDecimal({var}floatRec, Value, fvCurrency, 0{ignored for currency types}, 9999);

    //convert the array of char into an easy to access string
    digits := PChar(Addr(floatRec.Digits[0]));

    if floatRec.Exponent > 0 then
    begin
        //Check for positive or negative infinity (exponent = 32767)
        if floatRec.Exponent = 32767 then //David Heffernan says that currency can never be infinity. Even though i can't test it, i can at least try to handle it
        begin
            if floatRec.Negative = False then
                Result := 'INF'
            else
                Result := '-INF';
            Exit;
        end;

        {
            digits:    1234567 89
              exponent--------^ 7=7 digits on left of decimal mark
        }
        s := Copy(digits, 1, floatRec.Exponent);

        {
            for the value 10000:
                digits:   "1"
                exponent: 5
            Add enough zero's to digits to pad it out to exponent digits
        }
        if Length(s) < floatRec.Exponent then
            s := s+StringOfChar('0', floatRec.Exponent-Length(s));

        if Length(digits) > floatRec.Exponent then
            s := s+'.'+Copy(digits, floatRec.Exponent+1, 20);
    end
    else if floatRec.Exponent < 0 then
    begin
        //check for NaN (Exponent = -32768)
        if floatRec.Exponent = -32768 then  //David Heffernan says that currency can never be NotANumber. Even though i can't test it, i can at least try to handle it
        begin
            Result := 'NAN';
            Exit;
        end;

        {
            digits:   .000123456789
                         ^---------exponent
        }

        //Add zero, or more, "0"'s to the left
        s := '0.'+StringOfChar('0', -floatRec.Exponent)+digits;
    end
    else
    begin
        {
            Exponent is zero.

            digits:     .123456789
                            ^
        }
        if length(digits) > 0 then
            s := '0.'+digits
        else
            s := '0';
    end;

    if floatRec.Negative then
        s := '-'+s;

    Result := s;
end;

、、のエッジケースを除いて、これらNANの文字列をWindowsに渡すことができます。INF-INF

class function TGlobalization.GetCurrencyFormat(const DecimalString: WideString; const Locale: LCID): WideString;
var
    cch: Integer;
    ValueStr: WideString;
begin
    Locale
        LOCALE_INVARIANT
        LOCALE_USER_DEFAULT     <--- use this one (windows.pas)
        LOCALE_SYSTEM_DEFAULT
        LOCALE_CUSTOM_DEFAULT       (Vista and later)
        LOCALE_CUSTOM_UI_DEFAULT    (Vista and later)
        LOCALE_CUSTOM_UNSPECIFIED   (Vista and later)
}

    cch := Windows.GetCurrencyFormatW(Locale, 0, PWideChar(DecimalString), nil, nil, 0);
    if cch = 0 then
        RaiseLastWin32Error;

    SetLength(ValueStr, cch);
    cch := Windows.GetCurrencyFormatW(Locale, 0, PWideChar(DecimalString), nil, PWideChar(ValueStr), Length(ValueStr));
    if (cch = 0) then
        RaiseLastWin32Error;

    SetLength(ValueStr, cch-1); //they include the null terminator  /facepalm
    Result := ValueStr;
end;

FloatToDecimalStringと実装は読者のGetNumberFormat練習問題として残されています(実際にはまだfloatを記述していないので、通貨だけです。指数表記をどのように処理するかわかりません)。

そしてボブのヤーおじさん。Delphiで適切にローカライズされたフロートと通貨。

整数、日付、時刻、および日時を適切にローカライズする作業はすでに完了しています。

:すべてのコードはパブリックドメインにリリースされます。アトリビューションは必要ありません。

于 2011-08-17T21:46:33.320 に答える