CLng () и CDbl () сбрасывают десятичные дроби - PullRequest
0 голосов
/ 28 февраля 2019

Если я запускаю CLng("22.14") в редакторе Excel VBA на моем компьютере, я получаю ожидаемый результат, 22.Если я сделаю это на компьютерах некоторых международных коллег, то получится 2214.

CDbl делает то же самое.Я получаю 22.14, а они получают 2214.

Мои мысли: я предполагаю, что некоторые настройки определяют десятичный символ (и мои справедливо ".", А их - что-то другое).Мой поиск не дал никаких других идей или решений.

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Все функции преобразования чисел в 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 и вызывать базовые функции преобразования в oleaut32.dll напрямую с жестко заданным идентификатором локали.Например, чтобы получить 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
0 голосов
/ 28 февраля 2019

Двумя наиболее распространенными десятичными разделителями являются "." (США, Великобритания ...) и "," (Италия, Франция ...).Вы можете легко получить доступ к этому свойству из VBA, используя Application.DecimalSeparator (возвращая разделитель ОС).

Решение right не будет рассматривать "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").Но, честно говоря, это взломать.

...