在Delphi 1 中,使用FloatToStrF
或CurrToStrF
将自动使用DecimalSeparator
字符表示小数点。很遗憾DecimalSeparator
is declared in SysUtils as Char
1,2:
var
DecimalSeparator: Char;
虽然LOCALE_SDECIMAL
最多允许包含三个字符:
用于小数分隔符的字符,例如“。”在“3.14”或“,”在“3,14”中。此字符串允许的最大字符数为4,包括终止空字符。
这导致Delphi无法正确读取小数点分隔符;回过头来假设一个默认的小数分隔符“.
”:
DecimalSeparator := GetLocaleChar(DefaultLCID, LOCALE_SDECIMAL, '.');
在我的计算机上which is quite a character,这会导致浮动点和货币值错误地本地化,并带有U+002E(句号)小数点。
我我愿意直接调用Windows API函数,这些函数旨在将浮点值或货币值转换为本地化字符串:
除了这些函数之外,还需要一串图片代码,其中唯一允许的字符是:
U+0030
.. U+0039
).
),如果该数字是浮点值(U+002E
)将一个浮点或货币值转换为遵守这些规则的字符串,这将是一个很好的方法 1 ?例如
U+002D
1234567.893332
鉴于本地用户的语言环境(即我的电脑):
-1234567
来表示否定(例如-
).
to indicate a decimal point(例如--
)0123456789
to represent digits(例如 [删除了破坏SO javascript解析器的阿拉伯数字] )一个可怕的,可怕的,黑客,我可以使用:
,,
有关VCL使用的功能链的其他信息:
注意
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;
,单个character global is deprecated,并替换为另一个单字符小数点分隔符1 2 和当前版本的Delphi
答案 0 :(得分: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;
答案 1 :(得分:2)
Delphi确实提供了一个名为FloatToDecimal
的过程,它将浮点(例如Extended
)和Currency
值转换为有用的结构,以便进一步格式化。 e.g:
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
指数为-32768
( NaN ,而不是数字)
Digits: array[0..20] of Char = ""
Exponent: SmallInt = -32768
IsNegative: Boolean = False
表示值不是数字,例如NAN
指数为32767
( INF ,或 -INF )
Digits: array[0..20] of Char = ""
Exponent: SmallInt = 32767
IsNegative: Boolean = False
表示该值为正或负无穷大(取决于IsNegative
值),例如-INF
我们可以使用FloatToDecimal
作为起点来创建与“图片代码”无关的区域设置字符串。
然后,可以将此字符串传递给相应的Windows GetNumberFormat
或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
,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); //they include the null terminator /facepalm
Result := ValueStr;
end;
FloatToDecimalString
和GetNumberFormat
实现留给读者练习(因为我实际上还没有写过浮点数,只是货币 - 我不知道我是怎么回事将处理指数表示法。)
鲍勃是你的叔叔; Delphi下正确的本地化浮动和货币。
我已经完成了正确本地化整数,日期,时间和日期时间的工作。
注意:任何代码都会发布到公共域中。无需归属。