【问题标题】:VBA - Convert string to UNICODEVBA - 将字符串转换为 UNICODE
【发布时间】:2014-07-11 16:44:20
【问题描述】:

我需要将字符串 HTML 从西里尔字母和拉丁符号的混合转换为 UNICODE。

我尝试了以下方法:

Public HTML As String
    Sub HTMLsearch()

    GetHTML ("http://nfs.mobile.bg/pcgi/mobile.cgi?act=3&slink=6jkjov&f1=1")
    MsgBox HTML
    HTML = StrConv(HTML, vbUnicode)
    MsgBox HTML
End Sub

Function GetHTML(URL As String) As String
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", URL, False
        .Send
        HTML = .ResponseText
    End With
End Function

您可以看到 StrConv 之前和之后的内容。如果您想获取文件中的 html,可以使用以下代码:

Public HTML As String
    Sub HTMLsearch()

    GetHTML ("http://nfs.mobile.bg/pcgi/mobile.cgi?act=3&slink=6jkjov&f1=1")

    Dim path As String

    path = ThisWorkbook.path & "\html.txt"
    Open path For Output As #1
    Print #1, HTML
    Close #1

    HTML = StrConv(HTML, vbUnicode)

    path = ThisWorkbook.path & "\htmlUNICODE.txt"
    Open path For Output As #1
    Print #1, HTML
    Close #1
End Sub

Function GetHTML(URL As String) As String
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", URL, False
        .Send
        HTML = .ResponseText
    End With
End Function

想法?

【问题讨论】:

  • 这将有助于解释与您期望/希望它做什么相关的代码做什么(或不做什么)。即这里的实际问题是什么

标签: vba unicode cyrillic


【解决方案1】:

VBA 对 Unicode 的支持并不是那么好。

可以处理 Unicode 字符串,但您将无法看到带有 Debug.PrintMsgBox 的实际字符 - 它们将在那里显示为 ?

您可以将控制面板>区域和语言>管理选项卡>“非Unicode程序的当前语言”设置为“俄语”切换到不同的代码页,这样您就可以看到西里尔字母VBA 消息框中的字母而不是问号。但这只是表面上的改变。


你真正的问题在这里是别的东西。

服务器 (nfs.mobile.bg) 将文档作为Content-Type: text/html 发送。没有关于字符编码的信息。这意味着接收者必须自己找出字符编码。

浏览器通过查看响应字节流并进行猜测来做到这一点。在您的情况下,HTML 源代码中存在一个有用的 <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> 标记。因此,字节流应该被解释为Windows-1251,恰好是Windows中的Cyrillic ANSI代码页。

所以,我们这里甚至没有 Unicode!

在没有任何附加信息的情况下,XMLHTTP 对象的responseText 属性默认为us-ascii。来自西里尔字母的扩展字符在 ASCII 中不存在,因此它们将被转换为实际问号并丢失。这就是为什么你不能将responseText 用于任何事情的原因。

但是,响应的原始字节仍然可用,在responseBody属性中,它是Byte的数组。

在 VBA 中,您必须执行与浏览器相同的操作。您必须将字节流解释为特定字符集。 ADODB.Stream 对象可以为您做到这一点,而且非常简单:

' reference: "Microsoft XML, v6.0" (or any other version)
' reference: "Microsoft ActiveX Data Objects 6.1 library" (or any other version)
Option Explicit

Sub HTMLsearch()
    Dim url As String, html As String
    
    url = "http://nfs.mobile.bg/pcgi/mobile.cgi?act=3&slink=6jkjov&f1=1"
    html = GetHTML(url, "Windows-1251")
    
    ' Cyrillic characters are supported in Office, so they will appear correctly
    ActiveDocument.Range.InsertAfter html
End Sub

Function GetHTML(Url As String, Optional Charset As String = "UTF-8") As String
    Dim request As New MSXML2.XMLHTTP
    Dim converter As New ADODB.stream
    
    ' fetch page
    request.Open "GET", Url, False
    request.send
    
    ' write raw bytes to the stream
    converter.Open
    converter.Type = adTypeBinary
    converter.Write request.responseBody
    
    ' switch the stream to text mode and set charset
    converter.Position = 0
    converter.Type = adTypeText
    converter.Charset = Charset
    
    ' read text characters from the stream, close the stream
    GetHTML = converter.ReadText
    converter.Close
End Function

我一直在这里使用 MS Word 并调用 HTMLsearch() 正确地将西里尔字符写入页面。不过,对我来说,它们仍然在MsgBox 中显示为?,但现在这纯粹是一个显示问题,这是由于VBA 创建的UI 无法处理Unicode。

【讨论】:

  • @Tomalak :我不相信我见过更好的答案和解释。非常感谢您的支持!
  • @Vihar 感谢您的反馈! :)
  • 例如输入中的字节0xC1→使用代码页1251解释为字符Б→映射到Unicode中的U+0431(西里尔小写字母BE)(内存中的UTF-16表示:2字节0x0431
  • @Br.Bill 这是存储库中的一个问题/解决方法线程,一般看起来非常有用:github.com/VBA-tools/VBA-Web/issues/65
  • 谈论一个有教育意义的答案。这是读取俄罗斯网站的直接方法 - 虽然 charset 是 UTF-8,但你也解释了。
【解决方案2】:

我的生产订单数据来自许多国家。这是我能找到的唯一真正有效的 vba 函数。

Private Const CP_UTF8 = 65001

Private Declare Function MultiByteToWideChar Lib "kernel32" ( _
   ByVal CodePage As Long, ByVal dwFlags As Long, _
   ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, _
   ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long


Public Function sUTF8ToUni(bySrc() As Byte) As String
   ' Converts a UTF-8 byte array to a Unicode string
   Dim lBytes As Long, lNC As Long, lRet As Long

   lBytes = UBound(bySrc) - LBound(bySrc) + 1
   lNC = lBytes
   sUTF8ToUni = String$(lNC, Chr(0))
   lRet = MultiByteToWideChar(CP_UTF8, 0, VarPtr(bySrc(LBound(bySrc))), lBytes, StrPtr(sUTF8ToUni), lNC)
   sUTF8ToUni = Left$(sUTF8ToUni, lRet)
End Function

示例用法:

Dim sHTML As String
Dim bHTML() As Byte
bHTML = GetHTML("http://yoururlhere/myorderdata.php")
sHTML = sUTF8ToUni(bHTML)
sHTML = Mid(sHTML, 2)  'strip off Byte Order Mark: EF BB BF

【讨论】:

  • 您能解释一下“不起作用”是什么意思,并举一个我的功能失败的例子吗?
  • 此解决方案只能在 Windows 中运行。 Excel for Mac 无法做到这一点。它没有 kernel32 库。
猜你喜欢
  • 1970-01-01
  • 2016-11-03
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多