首页 > 解决方案 > CDec:带小数的参数字符串的国际语法

问题描述

我的 Excel 为所有内容(公式、界面、指南)设置了英文。我的 Windows 设置为“,”作为十进制符号和“。” 用于区域设置中的数字分组符号,因为我住在意大利。

如果我写这段代码:

    Dim v As Variant
    v = CDec("12345678901234567000,123456789")
    v = v + 50

结果在 Locals 窗口中显示为“12345678901234567050,123456789”(变量/十进制)。如果我将它发送到 msgbox,则相同。

如果我使用“。” 而不是“,”,结果是 12345678901234567000123456839。

在 VBA 中,当写数字时(以数字的形式,而不是字符串),我必须使用英文语法,即“。” 为十进制符号。

我相信我的示例代码会被具有英语区域设置的 Windows 错误地运行。

我怎样才能(修改它)使它在任何区域设置下正确运行?

标签: vbaregional-settings

解决方案


C*转换函数(CInt、等CLngCStr都设计为在计算机的当前语言环境中工作。他们将使用当前的小数分隔符,因此您正确地假设CDec将无法正确处理,具有不同小数点的系统上的硬编码。

相反,Str始终Val使用英文分隔符,但它们不支持Decimal.


所以想到的一种选择是在运行时获取小数点:

Dim v As Variant
v = CDec("12345678901234567000" & Application.International(xlDecimalSeparator) & "123456789")

但是应该注意的是,如果Application.UseSystemSeparatorsFalse并且Application.DecimalSeparator已经被更改,那么Application.International(xlDecimalSeparator)返回更改后的分隔符,而不是来自计算机语言环境的分隔符。因此,如果您不能保证UseSystemSeparators是,请不要使用此方法True


另一种选择是以十的幂除的形式表示小数位,这对于精确的定点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

(有关此代码的版本,该版本可以更好地控制允许包含的字符串,请参阅此答案的修订版 3。NUMPRS_STD接收的参数是要更改的参数。)


推荐阅读