如何在Excel VBA中将UTF-8转换为UTF-16?

问题描述

据我所知,Excel使用UTF-16表示字符串文字。我从控制台(Mac)/文件(Windows)中读取,在两种情况下,字符编码都混乱了。我必须找到在两个平台上都可以使用的解决方案,因此ADO流不是一个选择。我进行了一些调试,发现实际字节是:

Bytes     | displayed as | Should be | Correct byte
258,129   | Ă           | Á         | 193
258,356   | ĂŤ           | Í         | 205
313,176   | Ű           | Ű         | 219
313,144   | Ĺ           | Ő         | 213
258,347   | Ăś           | Ü         | 220
258,8211  | Ă–           | Ö         | 214
258,353   | Ăš           | Ú         | 218
258,8220  | Ă“           | Ó         | 211
258,8240  | É           | É         | 201

(来自古老的匈牙利测试用语ÁRVÍZTŰRŐTÜKÖRFÚRÓGÉP,其中包含我们所有的特殊字符)。 我正在寻找一种在Mac和Windows上都能生成正确字符串的算法。 谢谢!

解决方法

我必须解决此问题,所以提出了以下功能,可以成功转换128到255之间的字符

Private Function utf8ToUTF16(ByVal strText As String) As String
    Dim i&,l1%,l2%,l3%
    For i = 1 To Len(strText)
        l1 = Asc(Mid(strText,i,1))
        If i <> Len(strText) Then l2 = Asc(Mid(strText,i + 1,1))
        Select Case l1
        Case 194
            utf8ToUTF16 = utf8ToUTF16 & WorksheetFunction.Unichar(l2): i = i + 1
        Case 195
            utf8ToUTF16 = utf8ToUTF16 & WorksheetFunction.Unichar(l2 + &H40): i = i + 1
        Case 197
            utf8ToUTF16 = utf8ToUTF16 & WorksheetFunction.Unichar(l2 + &HC0): i = i + 1
        Case 203
            utf8ToUTF16 = utf8ToUTF16 & WorksheetFunction.Unichar(l2 + &H240): i = i + 1
        Case 226
            If l2 = 128 Then
                l3 = Asc(Mid(strText,i + 2,1))
                utf8ToUTF16 = utf8ToUTF16 & WorksheetFunction.Unichar(l3 + &H1F80)
                i = i + 2
            ElseIf l2 = 130 Then
                l3 = Asc(Mid(strText,1))
                utf8ToUTF16 = utf8ToUTF16 & WorksheetFunction.Unichar(l3 + &H2000)
                i = i + 2
            End If
        Case Else
            utf8ToUTF16 = utf8ToUTF16 & Chr(l1)
        End Select
    Next i
End Function

现在将“ ĂRVĂŤZTĹRĹTĹśKĂ–RFĂšRĂ”GÉP传递给此函数(从标准UTF-8编码文件读取)将返回“ÁRVÍZTŰRŐTÜKÖRFÚRÓGÉP”。

  • 注意:当然,这不是最有效的代码。每当我调用它时,我总是在尽可能短的字符串上使用它。目前,我使用它来解码cURL的结果,然后将整个HTML冻结。

编辑

现在我有一些时间来清理它。

Private Function utf8ToUTF16(ByVal strText As String) As String
    Dim i&,l1&,l2&,l3&,l4&,l&
    For i = 1 To Len(strText)
        l1 = Asc(Mid(strText,1))
        If i + 1 <= Len(strText) Then l2 = Asc(Mid(strText,1))
        If i + 2 <= Len(strText) Then l3 = Asc(Mid(strText,1))
        If i + 3 <= Len(strText) Then l4 = Asc(Mid(strText,i + 3,1))
        Select Case l1
        Case 1 To 127
            l = l1
        Case 194 To 223
            l = ((l1 And &H1F) * 2 ^ 6) Or (l2 And &H3F)
            i = i + 1
        Case 224 To 239
            l = ((l1 And &HF) * 2 ^ 12) Or ((l2 And &H3F) * 2 ^ 6) Or (l3 And &H3F)
            i = i + 2
        Case 240 To 255
            l = ((l1 And &H7) * 2 ^ 18) Or ((l2 And &H3F) * 2 ^ 12) Or ((l3 And &H3F) * 2 ^ 6) Or (l4 And &H3F)
            i = i + 4
        Case Else
            l = 63 ' question mark
        End Select
        utf8ToUTF16 = utf8ToUTF16 & IIf(l < 55296,WorksheetFunction.Unichar(l),"?")
    Next i
End Function

我意识到,高于55295(D7FF)的字符将不会出现,因此它将输出一个问号代替占位符。

,

我发现这个简单的 VBA 代码适用于文本文件中的西班牙重音字符。给定一个带有 UTF-8 双字符的字符串,它返回一个带有重音字符的字符串:

Function UTF8to16(str As String) As String
Dim position As Long,strConvert As String,codeReplace As Integer,strOut As String

strOut = str
position = InStr(strOut,Chr(195))

If position > 0 Then
    Do Until position = 0
        strConvert = Mid(strOut,position,2)
        codeReplace = Asc(Right(strConvert,1))
        If codeReplace < 255 Then
            strOut = Replace(strOut,strConvert,Chr(codeReplace + 64))
        Else
            strOut = Replace(strOut,Chr(34))
        End If
        position = InStr(strOut,Chr(195))
    Loop
End If

UTF8to16 = strOut

End Function