Функции преобразования C*
(CInt
, CLng
, CStr
и т. Д.) Предназначены для работы в текущей локали компьютера. Они будут использовать текущий десятичный разделитель, поэтому вы правы, предполагая, что CDec
не сможет правильно обработать жестко закодированный ,
в системе с другой десятичной точкой.
Напротив, Str
и Val
всегда работают с английскими разделителями, но они не поддерживают Decimal
.
Поэтому на ум приходит один вариант - получить десятичную точку во время выполнения :
Dim v As Variant
v = CDec("12345678901234567000" & Application.International(xlDecimalSeparator) & "123456789")
Следует отметить, однако, что если Application.UseSystemSeparators
равно False
и 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
тот, который нужно изменить.)