Delphi提供了一个名为FloatToDecimal
的过程,可以将浮点数(例如Extended
)和Currency
值转换为有用的结构以进行进一步格式化。例如:
FloatToDecimal(..., 1234567890.1234, ...);
给你:
TFloatRec
Digits: array[0..20] of Char = "12345678901234"
Exponent: SmallInt = 10
IsNegative: Boolean = True
“Exponent”表示小数点左侧的数字位数。
需要处理一些特殊情况:
Exponent is zero
Digits: array[0..20] of Char = "12345678901234"
Exponent: SmallInt = 0
IsNegative: Boolean = True
means there are no digits to the left of the decimal point, e.g. .12345678901234
Exponent is negative
Digits: array[0..20] of Char = "12345678901234"
Exponent: SmallInt = -3
IsNegative: Boolean = True
means you have to place zeros in between the decimal point and the first digit, e.g. .00012345678901234
Exponent is -32768
(NaN, not a number)
Digits: array[0..20] of Char = ""
Exponent: SmallInt = -32768
IsNegative: Boolean = False
means the value is Not a Number, e.g. NAN
Exponent is 32767
(INF, or -INF)
Digits: array[0..20] of Char = ""
Exponent: SmallInt = 32767
IsNegative: Boolean = False
means the value is either positive or negative infinity (depending on the IsNegative
value), e.g. -INF
我们可以使用FloatToDecimal
作为起点,创建一个与语言环境无关的"图片代码字符串"。
然后,将此字符串传递给适当的Windows GetNumberFormat
或GetCurrencyFormat
函数,以执行实际的正确本地化。
我编写了自己的CurrToDecimalString
和FloatToDecimalString
,将数字转换为所需的语言环境无关格式:
class function TGlobalization.CurrToDecimalString(const Value: Currency): string;
var
digits: string;
s: string;
floatRec: TFloatRec;
begin
FloatToDecimal(floatRec, Value, fvCurrency, 0, 9999);
digits := PChar(Addr(floatRec.Digits[0]));
if floatRec.Exponent > 0 then
begin
if floatRec.Exponent = 32767 then
begin
if floatRec.Negative = False then
Result := 'INF'
else
Result := '-INF';
Exit;
end;
s := Copy(digits, 1, floatRec.Exponent);
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
if floatRec.Exponent = -32768 then
begin
Result := 'NAN';
Exit;
end;
s := '0.'+StringOfChar('0', -floatRec.Exponent)+digits;
end
else
begin
if length(digits) > 0 then
s := '0.'+digits
else
s := '0';
end;
if floatRec.Negative then
s := '-'+s;
Result := s;
end;
除了NAN
、INF
和-INF
这些特殊情况外,我现在可以将这些字符串传递给Windows:
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);
Result := ValueStr;
end;
"
FloatToDecimalString
和GetNumberFormat
的实现留给读者自己练习(因为我实际上还没有写过浮点数,只写过货币-我不知道如何处理指数表示法)。
这样一来,Delphi下的浮点数和货币就可以正确本地化了。
我已经完成了整数、日期、时间和日期时间的正确本地化工作。
注意:任何代码都是公有领域。不需要归属。
"