CLng()和CDbl()删除小数

时间:2019-02-28 00:26:51

标签: excel vba internationalization type-conversion

如果我在PC的Excel VBA编辑器中运行CLng("22.14"),则会得到预期的结果22。如果我在某些国际同事的PC上执行此操作,它将产生2214

CDbl在做类似的事情。我得到22.14,他们得到2214

我的想法:我假设某个设置定义了小数字符(我的正确是“。”,而其他则是“。”)。我的搜索没有其他想法或解决方案。

2 个答案:

答案 0 :(得分:4)

VBA中的所有数字转换函数都支持区域设置,因此它们将忽略数千个分隔符和货币符号。 IsNumeric函数的行为方式相同:

Public Sub Example()
    'en-US locale
    Debug.Print IsNumeric("$1,1,1,1,1,")    'True
    Debug.Print CLng("$1,1,1,1,1,")         '11111
End Sub

我知道用于处理此问题的唯一主机不可知的解决方法(除了不将数字存储为String之外)是完全绕过内置的VBA强制转换,并调用基础的{{3 }}直接使用硬编码的区域设置ID。例如,要从美国本地化字符串中获取Double

Public Declare PtrSafe Function VarR8FromStr Lib "oleaut32" _
    (ByVal strIn As LongPtr, ByVal lcid As Long, ByVal dwFlags As Long, ByRef pdblOut As Double) As Long

Public Const EN_US As Long = 1033

Public Function DoubleFromEnUsString(converting As String) As Double
    Dim converted As Double, result As Long
    result = VarR8FromStr(StrPtr(converting), EN_US, 0, converted)
    If (result = 0) Then
        DoubleFromEnUsString = converted
    Else
        Err.Raise 5
    End If
End Function

...或Long

Public Declare PtrSafe Function VarI4FromStr Lib "oleaut32" _
    (ByVal strIn As LongPtr, ByVal lcid As Long, ByVal dwFlags As Long, ByRef plOut As Long) As Long

Public Const EN_US As Long = 1033

Public Function LongFromEnUsString(converting As String) As Long
    Dim converted As Long, result As Long
    result = VarI4FromStr(StrPtr(converting), EN_US, 0, converted)
    If (result = 0) Then
        LongFromEnUsString = converted
    Else
        Err.Raise 5
    End If
End Function

用法示例:

Public Sub Sample()
    Debug.Print LongFromEnUsString("12.34")     '12
    Debug.Print DoubleFromEnUsString("12.34")   '12.34
End Sub

答案 1 :(得分:3)

两个最常见的十进制分隔符是"."(美国,英国...)和","(意大利,法国...)。 您可以使用Application.DecimalSeparator(返回操作系统的分隔符)从VBA轻松访问此属性。

正确解决方案不是将"22.14"视为String,而是将其视为实数,这样,这种国际化问题就可以解决了。系统。

如果确实的这个数字不能与String相同(例如,您是从英语/美国API获取这些值,则向您发送反序列化的数字),然后您可以使用类似的功能:

Function InternationalCLng(ByVal st As String)

    Dim EnglishSep As Boolean: EnglishSep = ("." = Application.DecimalSeparator)
    If Not EnglishSep Then
        st = Replace(st, ".", Application.DecimalSeparator)
    End If
    InternationalCLng = CLng(st)

End Function

...将.替换为正确的DecimalSeparator,而使用InternationalCLng("22.14")。 但老实说,这是一个hack。