首页 > 解决方案 > 如何在 Excel VBA 中将 UTF-8 转换为 UTF-16?

问题描述

据我所知,Excel 使用 UTF-16 来表示字符串文字。我从控制台(Mac)/文件(Windows)读取,在这两种情况下,字符编码都是混乱的。我必须找到一个适用于两个平台的解决方案,所以 ADO 流不是一个选项。我做了一些调试,我看到实际字节是:

字节 | 显示为 | 应该是 | 正确的字节
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 上产生正确的字符串。谢谢!

标签: excelvbautf-8utf-16

解决方案


由于我必须解决这个问题,我想出了以下函数,它可以成功转换 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, i + 2, 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, i, 1))
        If i + 1 <= Len(strText) Then l2 = Asc(Mid(strText, i + 1, 1))
        If i + 2 <= Len(strText) Then l3 = Asc(Mid(strText, i + 2, 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)以上的字符不会出现,所以它会输出一个问号作为占位符。


推荐阅读