如何将浮点数或货币转换为本地化字符串?
在Delphi1中,使用FloatToStrF
或CurrToStrF
将自动使用DecimalSeparator
字符来表示小数点。不幸的是 DecimalSeparator
在 SysUtils 中声明为 Char< /code>1,2
:
var
DecimalSeparator: Char;
而 LOCALE_SDECIMAL
是最多允许三个字符:
用于小数点分隔符的字符,例如“.”在“3.14”或“3,14”中的“,”。该字符串允许的最大字符数为四个,包括终止空字符。
这会导致Delphi无法正确读取小数点分隔符;回退到默认的小数点分隔符“.
”:
DecimalSeparator := GetLocaleChar(DefaultLCID, LOCALE_SDECIMAL, '.');
在我的计算机上,这是一个相当大的字符,这会导致浮点和货币值被错误地本地化为U+002E(句号)小数点。
我愿意直接调用 Windows API 函数,这些函数旨在将浮点或货币值转换为本地化字符串:
除外这些函数采用一串图片代码,其中唯一允许的字符是:
- 字符“0”到“9” (
U+0030
..U+0039
) - 如果数字是浮点值 (
),则保留一位小数点 (
).
) U+002E - 如果数字是负值,则在第一个字符位置添加减号 (
U+002D
)
什么是一个好方法1将浮点或货币值转换为遵守这些规则的字符串?例如
1234567.893332
-1234567
鉴于本地用户的区域设置(即我的计算机):
- 可能不会使用
-
来表示否定(例如--
) - 可能不使用
。
指示小数点(例如,,
) - 可能不会使用拉丁字母
0123456789
来表示数字(例如[删除了导致崩溃的阿拉伯数字javascript解析器])
一个可怕的,可怕的黑客,我可以使用:
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使用的函数链的附加信息:
注意< /strong>
DecimalSeparator: Char
,单个 字符全局已弃用,并替换为另一个单字符小数分隔符
1 在我的 Delphi 版本中
2 以及当前版本的 Delphi
In Delphi1, using FloatToStrF
or CurrToStrF
will automatically use the DecimalSeparator
character to represent a decimal mark. Unfortunately DecimalSeparator
is declared in SysUtils as Char
1,2:
var
DecimalSeparator: Char;
While the LOCALE_SDECIMAL
is allowed to be up to three characters:
Character(s) used for the decimal separator, for example, "." in "3.14" or "," in "3,14". The maximum number of characters allowed for this string is four, including a terminating null character.
This causes Delphi to fail to read the decimal separator correctly; falling back to assume a default decimal separator of ".
":
DecimalSeparator := GetLocaleChar(DefaultLCID, LOCALE_SDECIMAL, '.');
On my computer, which is quite a character, this cause floating point and currency values to be incorrectly localized with a U+002E (full stop) decimal mark.
i am willing to call the Windows API functions directly, which are designed to convert floating point, or currency, values into a localized string:
Except these functions take a string of picture codes, where the only characters allowed are:
- Characters "0" through "9" (
U+0030
..U+0039
) - One decimal point (
.
) if the number is a floating-point value (U+002E
) - A minus sign in the first character position if the number is a negative value (
U+002D
)
What would be a good way1 to convert a floating point, or currency, value to a string that obeys those rules? e.g.
1234567.893332
-1234567
given that the local user's locale (i.e. my computer):
- might not use a
-
to indicate negative (e.g.--
) - might not use a
.
to indicate a decimal point (e.g.,,
) - might not use the latin alphabet
0123456789
to represent digits (e.g. [removed arabic digits that crash SO javascript parser])
A horrible, horrible, hack, which i could use:
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;
Additional info on the chain of functions the VCL uses:
FloatToStrF
andCurrToStrF
calls:FloatToText
calls:
Note
DecimalSeparator: Char
, the single character global is deprecated, and replaced with another single character decimal separator
1 in my version of Delphi
2 and in current versions of Delphi
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Delphi 确实提供了一个名为
FloatToDecimal
的过程,它将浮点(例如扩展
)和Currency
值转换为有用的结构以供进一步格式化。例如:给出:
其中
Exponent
给出小数点左侧的位数。有一些特殊情况需要处理:
指数为零
表示小数点左边没有数字,例如
.12345678901234
指数为负
表示您必须在小数点和第一位数字之间添加零,例如
.00012345678901234
指数为
-32768
(NaN,不是数字)表示该值不是数字,例如
NAN
指数为
32767
(INF 或 -INF)表示该值为正无穷大或负无穷大(取决于
IsNegative
值),例如-INF
我们可以使用
FloatToDecimal
作为起点来创建与区域设置无关的“图片代码”字符串。然后可以将此字符串传递给适当的 Windows
GetNumberFormat
或GetCurrencyFormat
函数以执行实际的正确本地化。我编写了自己的
CurrToDecimalString
和FloatToDecimalString
,它们将数字转换为所需的独立于语言环境的格式:除了
NAN
、INF 的边缘情况之外
和-INF
,我现在可以将这些字符串传递到 Windows:还有鲍勃的叔叔; Delphi 下正确本地化的浮动和货币。
我已经完成了正确本地化整数、日期、时间和日期时间的工作。
Delphi does provide a procedure called
FloatToDecimal
that converts floating point (e.g.Extended
) andCurrency
values into a useful structure for further formatting. e.g.:gives you:
Where
Exponent
gives the number of digits to the left of decimal point.There are some special cases to be handled:
Exponent is zero
means there are no digits to the left of the decimal point, e.g.
.12345678901234
Exponent is negative
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)means the value is Not a Number, e.g.
NAN
Exponent is
32767
(INF, or -INF)means the value is either positive or negative infinity (depending on the
IsNegative
value), e.g.-INF
We can use
FloatToDecimal
as a starting point to create a locale-independent string of "pictures codes".This string can then be passed to appropriate Windows
GetNumberFormat
orGetCurrencyFormat
functions to perform the actual correct localization.i wrote my own
CurrToDecimalString
andFloatToDecimalString
which convert numbers into the required locale independent format:Aside from the edge cases of
NAN
,INF
and-INF
, i can now pass these strings to Windows:And Bob's yer uncle; properly localized floats and currencies under Delphi.
i already went through the work of properly localizing Integers, Dates, Times, and Datetimes.
好吧,这可能不是您想要的,但它适用于 D2007 及更高版本。
线程安全等等。
Ok, this may not be what you want, but it works with D2007 and up.
Thread safe and all.