标题: VBS字符串与UTF-16(Unicode)
作者: Demon
链接: https://demon.tw/programming/vbs-utf-16.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
在写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
赞赏微信赞赏支付宝赞赏
随机文章: