VBA can call into the COM run-time parsing functions to get some serious help with parsing. In this example I show string being parsed to a numeric type. This code also handles exponential notation in case you not sufficiently impressed.
One point of note is that if you pass a number with 4 or fewer decimal places then the COM runtime will by default parse to the Currency type. I think most programmers would expect as Double so I've added some post-processing code whilst keeping the Currency option open.
If you really want a currency then I suggest you read this blog post where I parse currencies.
modVarNumFromStr Standard Module
- Option Explicit
- '*
- '* Brought to you by the Excel Development Platform blog
- '* https://exceldevelopmentplatform.blogspot.com/2018/12
- '*
- Private Type NUMPARSE
- cDig As Long
- dwInFlags As Long
- dwOutFlags As Long
- cchUsed As Long
- nBaseShift As Long
- nPwr10 As Long
- End Type
- Private Declare Function VarParseNumFromStr Lib "oleaut32" (ByVal strIn As Long, ByVal LCID As Long, _
- ByVal dwFlags As Long, ByRef numprs As NUMPARSE, ByRef rgbDig As Byte) As Long
- Private Declare Function VarNumFromParseNum Lib "oleaut32" (ByRef pnumprs As NUMPARSE, _
- ByRef rgbDig As Byte, ByVal dwVtBits As Long, ByRef pvar As Variant) As Long
- Sub TestVarNumFromStr()
- Dim v(0 To 9)
- v(0) = VarNumFromStr("14")
- Debug.Assert v(0) = 14
- Debug.Assert VarType(v(0)) = VbVarType.vbInteger
- v(1) = VarNumFromStr("15.1234")
- Debug.Assert v(1) = 15.1234
- Debug.Assert VarType(v(1)) = VbVarType.vbCurrency
- v(2) = VarNumFromStr("15.11111")
- Debug.Assert v(2) = 15.11111
- Debug.Assert VarType(v(2)) = VbVarType.vbDouble
- v(3) = VarNumFromStr("1.512E6")
- Debug.Assert v(3) = 1512000
- Debug.Assert VarType(v(3)) = VbVarType.vbLong
- v(4) = VarNumFromStr("1.512E-6")
- Debug.Assert v(4) = 0.000001512
- Debug.Assert VarType(v(4)) = VbVarType.vbDouble
- Stop
- End Sub
- Public Function VarNumFromStr(ByRef sText As String, Optional bConvertCurrencyToDouble As Boolean = True) As Variant
- Dim rgbDig() As Byte
- Dim uNUMPARSE As NUMPARSE
- Dim lLen As Long
- lLen = VBA.Len(sText)
- If lLen > 0 Then
- ReDim rgbDig(lLen - 1)
- '* https://technet.microsoft.com/ru-ru/ms221690(v=vs.90)
- With uNUMPARSE
- .cDig = lLen
- .dwInFlags = &H1FFF& 'NUMPRS_STD
- End With
- '* https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-varparsenumfromstr
- If VarParseNumFromStr(StrPtr(sText), 0, 0, uNUMPARSE, rgbDig(0)) = 0 Then
- '* https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-varnumfromparsenum#vtbit_decimal
- If VarNumFromParseNum(uNUMPARSE, rgbDig(0), 2047, VarNumFromStr) = 0 Then
- '* do we need any post-processing
- If bConvertCurrencyToDouble And InStr(1, sText, ".", vbTextCompare) > 0 And _
- VarType(VarNumFromStr) = vbCurrency Then
- VarNumFromStr = CDbl(VarNumFromStr) '* convert decimal currency
- End If
- Else
- Err.Raise vbObjectError, , "#Error whilst parsing '" & sText & "'!"
- End If
- Else
- Err.Raise vbObjectError, , "#Error whilst parsing '" & sText & "'!"
- End If
- End If
- End Function
No comments:
Post a Comment