CDec:带小数的参数字符串的国际语法
CDec: international syntax for argument string with decimals
我的 Excel 所有内容(公式、界面、指南)都设置为英文。
我的 Windows 设置为用“,”表示小数点符号,用“.”表示。对于区域设置中的数字分组符号,因为我住在意大利。
如果我写这段代码:
Dim v As Variant
v = CDec("12345678901234567000,123456789")
v = v + 50
结果在 Locals window 中显示为“12345678901234567050,123456789”(Variant/Decimal)。如果我 msgbox 也一样。
如果我用“.”而不是“,”,结果是 12345678901234567000123456839.
在VBA中,当写数字(以数字形式,而不是字符串形式)时,我必须使用英文语法,即“.”小数点符号。
我相信我的示例代码会 运行 错误地被 Windows 使用英语区域设置。
我怎样才能(将其修改为)使其 运行 正确地适应任何区域设置?
C*
转换函数(CInt
、CLng
、CStr
等)都设计用于在计算机的当前区域设置中工作。他们将使用当前的小数点分隔符,因此您假设 CDec
将无法在具有不同小数点的系统上正确处理硬编码 ,
是正确的。
相反,Str
和Val
始终使用英文分隔符,但不支持Decimal
。
所以想到的一个选择是获取小数点 at runtime:
Dim v As Variant
v = CDec("12345678901234567000" & Application.International(xlDecimalSeparator) & "123456789")
不过需要注意的是,如果Application.UseSystemSeparators
是False
,而Application.DecimalSeparator
已经改了,那么Application.International(xlDecimalSeparator)
会变成return that changed separator,而不是那个来的从计算机语言环境。所以如果你不能保证 UseSystemSeparators
是 True
.
就不要使用这个方法
另一种选择是用十的幂除的形式来表示小数位,这与精确的fixed-point Decimal
数据类型相匹配:
Dim v As Variant
v = CDec("12345678901234567000123456789") / CDec("1000000000")
另一种选择是自定义 "CDec" 在特定语言环境中明确工作,并始终在该语言环境中对字符串进行硬编码:
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function VarDecFromStr Lib "OleAut32.dll" (ByVal strIn As LongPtr, ByVal lcid As Long, ByVal dwFlags As Long, ByRef pdecOut As Variant) As Long
#Else
Private Declare Function VarDecFromStr Lib "OleAut32.dll" (ByVal strIn As Long, ByVal lcid As Long, ByVal dwFlags As Long, ByRef pdecOut As Variant) As Long
#End If
Private Const LOCALE_INVARIANT As Long = &H7F&
Private Const S_OK As Long = &H0
Public Function ParseDecimalFromEnUsString(ByVal s As String) As Variant
Dim hr As Long
hr = VarDecFromStr(StrPtr(s), LOCALE_INVARIANT, 0, ParseDecimalFromEnUsString)
If hr <> S_OK Then
Err.Raise 5, , "Cannot parse the string. Error " & Hex$(hr)
End If
End Function
? ParseDecimalFromEnUsString("12345678901234567000.123456789")
12345678901234567000,123456789
? TypeName(ParseDecimalFromEnUsString("12345678901234567000.123456789"))
Decimal
(对于此代码的一个版本,可以更好地控制此答案的 what the string is allowed to contain, see revision 3。接收 NUMPRS_STD
的参数是要更改的参数。)
我的 Excel 所有内容(公式、界面、指南)都设置为英文。 我的 Windows 设置为用“,”表示小数点符号,用“.”表示。对于区域设置中的数字分组符号,因为我住在意大利。
如果我写这段代码:
Dim v As Variant
v = CDec("12345678901234567000,123456789")
v = v + 50
结果在 Locals window 中显示为“12345678901234567050,123456789”(Variant/Decimal)。如果我 msgbox 也一样。
如果我用“.”而不是“,”,结果是 12345678901234567000123456839.
在VBA中,当写数字(以数字形式,而不是字符串形式)时,我必须使用英文语法,即“.”小数点符号。
我相信我的示例代码会 运行 错误地被 Windows 使用英语区域设置。
我怎样才能(将其修改为)使其 运行 正确地适应任何区域设置?
C*
转换函数(CInt
、CLng
、CStr
等)都设计用于在计算机的当前区域设置中工作。他们将使用当前的小数点分隔符,因此您假设 CDec
将无法在具有不同小数点的系统上正确处理硬编码 ,
是正确的。
相反,Str
和Val
始终使用英文分隔符,但不支持Decimal
。
所以想到的一个选择是获取小数点 at runtime:
Dim v As Variant
v = CDec("12345678901234567000" & Application.International(xlDecimalSeparator) & "123456789")
不过需要注意的是,如果Application.UseSystemSeparators
是False
,而Application.DecimalSeparator
已经改了,那么Application.International(xlDecimalSeparator)
会变成return that changed separator,而不是那个来的从计算机语言环境。所以如果你不能保证 UseSystemSeparators
是 True
.
另一种选择是用十的幂除的形式来表示小数位,这与精确的fixed-point Decimal
数据类型相匹配:
Dim v As Variant
v = CDec("12345678901234567000123456789") / CDec("1000000000")
另一种选择是自定义 "CDec" 在特定语言环境中明确工作,并始终在该语言环境中对字符串进行硬编码:
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function VarDecFromStr Lib "OleAut32.dll" (ByVal strIn As LongPtr, ByVal lcid As Long, ByVal dwFlags As Long, ByRef pdecOut As Variant) As Long
#Else
Private Declare Function VarDecFromStr Lib "OleAut32.dll" (ByVal strIn As Long, ByVal lcid As Long, ByVal dwFlags As Long, ByRef pdecOut As Variant) As Long
#End If
Private Const LOCALE_INVARIANT As Long = &H7F&
Private Const S_OK As Long = &H0
Public Function ParseDecimalFromEnUsString(ByVal s As String) As Variant
Dim hr As Long
hr = VarDecFromStr(StrPtr(s), LOCALE_INVARIANT, 0, ParseDecimalFromEnUsString)
If hr <> S_OK Then
Err.Raise 5, , "Cannot parse the string. Error " & Hex$(hr)
End If
End Function
? ParseDecimalFromEnUsString("12345678901234567000.123456789")
12345678901234567000,123456789
? TypeName(ParseDecimalFromEnUsString("12345678901234567000.123456789"))
Decimal
(对于此代码的一个版本,可以更好地控制此答案的 what the string is allowed to contain, see revision 3。接收 NUMPRS_STD
的参数是要更改的参数。)