How can I URL encode a string in Excel VBA?

后端 未结 15 1913
闹比i
闹比i 2020-11-22 11:39

Is there a built-in way to URL encode a string in Excel VBA or do I need to hand roll this functionality?

相关标签:
15条回答
  • 2020-11-22 11:50

    Version of the above supporting UTF8:

    Private Const CP_UTF8 = 65001
    
    #If VBA7 Then
      Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32" ( _
        ByVal CodePage As Long, _
        ByVal dwFlags As Long, _
        ByVal lpWideCharStr As LongPtr, _
        ByVal cchWideChar As Long, _
        ByVal lpMultiByteStr As LongPtr, _
        ByVal cbMultiByte As Long, _
        ByVal lpDefaultChar As Long, _
        ByVal lpUsedDefaultChar As Long _
        ) As Long
    #Else
      Private Declare Function WideCharToMultiByte Lib "kernel32" ( _
        ByVal CodePage As Long, _
        ByVal dwFlags As Long, _
        ByVal lpWideCharStr As Long, _
        ByVal cchWideChar As Long, _
        ByVal lpMultiByteStr As Long, _
        ByVal cbMultiByte As Long, _
        ByVal lpDefaultChar As Long, _
        ByVal lpUsedDefaultChar As Long _
        ) As Long
    #End If
    
    Public Function UTF16To8(ByVal UTF16 As String) As String
    Dim sBuffer As String
    Dim lLength As Long
    If UTF16 <> "" Then
        #If VBA7 Then
            lLength = WideCharToMultiByte(CP_UTF8, 0, CLngPtr(StrPtr(UTF16)), -1, 0, 0, 0, 0)
        #Else
            lLength = WideCharToMultiByte(CP_UTF8, 0, StrPtr(UTF16), -1, 0, 0, 0, 0)
        #End If
        sBuffer = Space$(lLength)
        #If VBA7 Then
            lLength = WideCharToMultiByte(CP_UTF8, 0, CLngPtr(StrPtr(UTF16)), -1, CLngPtr(StrPtr(sBuffer)), LenB(sBuffer), 0, 0)
        #Else
            lLength = WideCharToMultiByte(CP_UTF8, 0, StrPtr(UTF16), -1, StrPtr(sBuffer), LenB(sBuffer), 0, 0)
        #End If
        sBuffer = StrConv(sBuffer, vbUnicode)
        UTF16To8 = Left$(sBuffer, lLength - 1)
    Else
        UTF16To8 = ""
    End If
    End Function
    
    Public Function URLEncode( _
       StringVal As String, _
       Optional SpaceAsPlus As Boolean = False, _
       Optional UTF8Encode As Boolean = True _
    ) As String
    
    Dim StringValCopy As String: StringValCopy = IIf(UTF8Encode, UTF16To8(StringVal), StringVal)
    Dim StringLen As Long: StringLen = Len(StringValCopy)
    
    If StringLen > 0 Then
        ReDim Result(StringLen) As String
        Dim I As Long, CharCode As Integer
        Dim Char As String, Space As String
    
      If SpaceAsPlus Then Space = "+" Else Space = "%20"
    
      For I = 1 To StringLen
        Char = Mid$(StringValCopy, I, 1)
        CharCode = Asc(Char)
        Select Case CharCode
          Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126
            Result(I) = Char
          Case 32
            Result(I) = Space
          Case 0 To 15
            Result(I) = "%0" & Hex(CharCode)
          Case Else
            Result(I) = "%" & Hex(CharCode)
        End Select
      Next I
      URLEncode = Join(Result, "")
    
    End If
    End Function
    

    Enjoy!

    0 讨论(0)
  • 2020-11-22 11:52

    One more solution via htmlfile ActiveX:

    Function EncodeUriComponent(strText)
        Static objHtmlfile As Object
        If objHtmlfile Is Nothing Then
            Set objHtmlfile = CreateObject("htmlfile")
            objHtmlfile.parentWindow.execScript "function encode(s) {return encodeURIComponent(s)}", "jscript"
        End If
        EncodeUriComponent = objHtmlfile.parentWindow.encode(strText)
    End Function
    

    Declaring htmlfile DOM document object as static variable gives the only small delay when called first time due to init, and makes this function very fast for numerous calls, e. g. for me it converts the string of 100 chars length 100000 times in 2 seconds approx..

    0 讨论(0)
  • 2020-11-22 11:54

    (Bump on an old thread). Just for kicks, here's a version that uses pointers to assemble the result string. It's about 2x - 4x as fast as the faster second version in the accepted answer.

    Public Declare PtrSafe Sub Mem_Copy Lib "kernel32" _
        Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    
    Public Declare PtrSafe Sub Mem_Read2 Lib "msvbvm60" _
        Alias "GetMem2" (ByRef Source As Any, ByRef Destination As Any)
    
    Public Function URLEncodePart(ByRef RawURL As String) As String
    
        Dim pChar As LongPtr, iChar As Integer, i As Long
        Dim strHex As String, pHex As LongPtr
        Dim strOut As String, pOut As LongPtr
        Dim pOutStart As LongPtr, pLo As LongPtr, pHi As LongPtr
        Dim lngLength As Long
        Dim cpyLength As Long
        Dim iStart As Long
    
        pChar = StrPtr(RawURL)
        If pChar = 0 Then Exit Function
    
        lngLength = Len(RawURL)
        strOut = Space(lngLength * 3)
        pOut = StrPtr(strOut)
        pOutStart = pOut
        strHex = "0123456789ABCDEF"
        pHex = StrPtr(strHex)
    
        iStart = 1
        For i = 1 To lngLength
            Mem_Read2 ByVal pChar, iChar
            Select Case iChar
                Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126
                  ' Ok
                Case Else
                    If iStart < i Then
                        cpyLength = (i - iStart) * 2
                        Mem_Copy ByVal pOut, ByVal pChar - cpyLength, cpyLength
                        pOut = pOut + cpyLength
                    End If
    
                    pHi = pHex + ((iChar And &HF0) / 8)
                    pLo = pHex + 2 * (iChar And &HF)
    
                    Mem_Read2 37, ByVal pOut
                    Mem_Read2 ByVal pHi, ByVal pOut + 2
                    Mem_Read2 ByVal pLo, ByVal pOut + 4
                    pOut = pOut + 6
    
                    iStart = i + 1
            End Select
            pChar = pChar + 2
        Next
    
        If iStart <= lngLength Then
            cpyLength = (lngLength - iStart + 1) * 2
            Mem_Copy ByVal pOut, ByVal pChar - cpyLength, cpyLength
            pOut = pOut + cpyLength
        End If
    
        URLEncodePart = Left$(strOut, (pOut - pOutStart) / 2)
    
    End Function
    
    0 讨论(0)
  • 2020-11-22 11:55

    This snippet i have used in my application to encode the URL so may this can help you to do the same.

    Function URLEncode(ByVal str As String) As String
            Dim intLen As Integer
            Dim x As Integer
            Dim curChar As Long
            Dim newStr As String
            intLen = Len(str)
            newStr = ""
    
            For x = 1 To intLen
                curChar = Asc(Mid$(str, x, 1))
    
                If (curChar < 48 Or curChar > 57) And _
                    (curChar < 65 Or curChar > 90) And _
                    (curChar < 97 Or curChar > 122) Then
                                    newStr = newStr & "%" & Hex(curChar)
                Else
                    newStr = newStr & Chr(curChar)
                End If
            Next x
    
            URLEncode = newStr
        End Function
    
    0 讨论(0)
  • 2020-11-22 11:56

    The accepted answer's code stopped on a Unicode error in Access 2013, so I wrote a function for myself with high readability that should follow RFC 3986 according to Davis Peixoto, and cause minimal trouble in various environments.

    Note: The percent sign itself must be replaced first, or it will double-encode any previously encoded characters. Replacing space with + was added, not to conform with RFC 3986, but to provide links that don't break due to formatting. It is optional.

    Public Function URLEncode(str As Variant) As String
        Dim i As Integer, sChar() As String, sPerc() As String
        sChar = Split("%|!|*|'|(|)|;|:|@|&|=|+|$|,|/|?|#|[|]| ", "|")
        sPerc = Split("%25 %21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %23 %5B %5D +", " ")
        URLEncode = Nz(str)
        For i = 0 To 19
            URLEncode = Replace(URLEncode, sChar(i), sPerc(i))
        Next i
    End Function
    
    0 讨论(0)
  • 2020-11-22 12:00

    Although, this one is very old. I have come up with a solution based in this answer:

    Dim ScriptEngine As ScriptControl
    Set ScriptEngine = New ScriptControl
    ScriptEngine.Language = "JScript"
    
    ScriptEngine.AddCode "function encode(str) {return encodeURIComponent(str);}"
    Dim encoded As String
    encoded = ScriptEngine.Run("encode", "€ömE.sdfds")
    

    Add Microsoft Script Control as reference and you are done.

    Just a side note, because of the JS part, this is fully UTF-8-compatible. VB will convert correctly from UTF-16 to UTF-8.

    0 讨论(0)
提交回复
热议问题