VBS字符串与UTF-16(Unicode)

标签: , , , ,

在写VbsJson类的时候要用到UTF-16的知识,所以研究了一下UTF-16。那么VBS字符串内部编码是不是UTF-16呢?

VBS字符串的内部实现》中谈到VBS字符串内部是以wchar_t来实现的,而MSDN在《Unicode (Windows)》写道:

Unicode-enabled functions are described in Conventions for Function Prototypes. These functions use UTF-16 (wide character) encoding, which is the most common encoding of Unicode and the one used for native Unicode encoding on Windows operating systems.

VBS内部使用的是支持Unicode的Windows API函数,所以VBS字符串应该是支持UTF-16的。

我们平时见到的字符基本都在BMP(基本多文种平面)内,UCS-2编码也一样可以支持BMP内的所有字符,那么VBS字符串内部使用的是UCS-2还是UTF-16?为了测试,我特地选了一个不在BMP内的汉字“𪚥”(U+2A6A5,由四个繁体龙字组成,你的系统不一定能显示)。

'Author: Demon
'Website: https://demon.tw
'Date: 2012/5/6
s = "𪚥"
WScript.Echo s
WScript.Echo Len(s)
For i = 1 To Len(s)
    c = Mid(s, i, 1)
    WScript.Echo Hex(AscW(c))
Next

运行后可以发现,VBS能够正确的显示该汉字,说明VBS字符串的内部编码是UTF-16而不是UCS-2。

但是Len函数的返回值竟然是2而不是1,为什么呢?因为在UTF-16中,BMP之外的字符需要2个16-bit的代理对(surrogate pair)来表示,而Len函数返回的是字符串中含有多少个这样的16-bit码元。也就是说,如果字符串中含有BMP之外的字符,那么使用VBS的字符串函数会存在潜在的BUG。

最后输出的是D869 DEA5,这正好是该汉字在UTF-16中的代理对,进一步证明了VBS字符串内部使用的是UTF-16编码。

验证完VBS字符串内部使用的是UTF-16编码了,我再说一下如何获取一个字符的Unicode代码点(code point),以及如果将Unicode代码点转换成对应的字符。

我们都知道AscW函数可以获取一个字符的Unicode代码点,但是AscW函数的返回值是0~65535,也就是只能获取BMP内字符的代码点,那么怎么样获取任意Unicode字符的代码点呢?为此我写了一个ToCodePoint函数:

'Author: Demon
'Website: https://demon.tw
'Date: 2012/5/6
s = "𪚥"
WScript.Echo ToCodePoint(s), Hex(ToCodePoint(s))

'return code point of a character
Function ToCodePoint(s)
    Dim uni, uni2
    uni = CLng("&H" & Hex(AscW(s)))
    If (uni >= &HD800&) And (uni <= &HDBFF&) Then
        uni2 = Mid(s, 2, 1)
        If uni2 = "" Then
            Err.Raise 8732, "ToCodePoint", _
            "Invalid  surrogate pair"
        End If
        uni2 = CLng("&H" & Hex(AscW(uni2)))
        uni = &H10000 + (((uni - &HD800&) * 2 ^ 10) Or (uni2 - &HDC00&))
    End If
    ToCodePoint = uni
End Function

我们也知道ChrW函数可以返回代码点对应的Unicode字符,但是ChrW函数同样只支持0~65535的范围。我也写了一个FromCodePoint函数:

'Author: Demon
'Website: https://demon.tw
'Date: 2012/5/6
WScript.Echo FromCodePoint(&H2A6A5)

'return a character from code point
Function FromCodePoint(n)
    Dim s1, s2
    If n < 0 Or n > &H10FFFF Then
        Err.Raise 8732, "FromCodePoint", _
        "Code point must be in 0-0x10FFFF"
    ElseIf n < &H10000 Then
        FromCodePoint = ChrW(n)
    Else
        n = n - &H10000
        s1 = &HD800 Or ((n \ 2 ^ 10) And &H3FF)
        s2 = &HDC00 Or (n And &H3FF)
        FromCodePoint = ChrW(s1) & ChrW(s2)
    End If
End Function

本文写得很乱,看不懂就忽略吧。

参考链接:http://zh.wikipedia.org/wiki/UTF-16

赞赏

微信赞赏支付宝赞赏

随机文章:

  1. 对VBS效率的再思考——处理二进制数据
  2. 用C语言实现PHP的dirname函数
  3. VB使用WebBrowser读取网页中iframe的内容
  4. 为OpenWrt编译Shadowsocks-libev
  5. Windows 7在桌面创建宽带连接快捷方式

留下回复