在博文《使用VBA在Office中输入特殊字符(1/3)》中我们知道月亮符号的字符代码为0x1F319【0x为16进制标识,在VBA中使用&H前缀】。
在Word中录制得到的代码如下。
Sub WordInsertMoon()
Selection.InsertSymbol Font:="Segoe UI Symbol", CharacterNumber:=-10180, _
Unicode:=True
Selection.InsertSymbol Font:="Segoe UI Symbol", CharacterNumber:=-8423, _
Unicode:=True
End Sub
使用Windows中的计算器可以轻松进行进制转换,如下图所示。其中的-10180
和-8423
和字符代码0x1F319
的不同进制转换如下,似乎这几个数字之间也看不出什么关系。
如果看一下-10180
和-8423
的低4位,可以拆分为:D8,3C,DF,19,对应的十进制为:216,60,223,25,这就是Byte数组中的4个元素,只是顺序不同而已。
字符代码(0x1F319
)和这两个数字的关系是什么呢?先来看一下UTF-16(Unicde编码的一种实现形式)的标准文档RFC2781。
https://tools.ietf.org/html/rfc2781
2.1 Encoding UTF-16Encoding of a single character from an ISO 10646 character value to
UTF-16 proceeds as follows. Let U be the character number, no greater
than 0x10FFFF.
If U < 0x10000, encode U as a 16-bit unsigned integer and
terminate.Let U’ = U - 0x10000. Because U is less than or equal to
0x10FFFF,
U’ must be less than or equal to 0xFFFFF. That is, U’ can be
represented in 20 bits.Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800
and
0xDC00, respectively. These integers each have 10 bits free to
encode the character value, for a total of 20 bits.Assign the 10 high-order bits of the 20-bit U’ to the 10
low-order
bits of W1 and the 10 low-order bits of U’ to the 10 low-order
bits of W2. Terminate.Graphically, steps 2 through 4 look like: U’ = yyyyyyyyyyxxxxxxxxxx
W1 = 110110yyyyyyyyyy W2 = 110111xxxxxxxxxx
对于月亮字符,U=0x1F319,符合大于0x10000,并且小于0x10FFFF
110110
,W2高位6比特为110111
-10180
和-8423
,和本文第一个截图中的两个数字是相同的,这就是Word录制宏中两个负数的由来(UTF-16中使用无符号整数,如果最高Bit位为1,当作符号整数进行解析时,则代表负整数)。这里提供一段代码实现这个编码格式的计算。
Function UTF16(sHex As String, Optional sMode As String = "HEX") As String
Dim lByte, hByte, arrRes
' &HDC00 = 56320, &HD800 = 55296
lByte = Hex(56320 Or (&H3FF And Application.Hex2Dec(sHex)))
hByte = Hex(55296 Or ((&HFFC00 And (Application.Hex2Dec(sHex) - &H10000)) / &H400))
arrRes = Array(Right(hByte, 2), Left(hByte, 2), Right(lByte, 2), Left(lByte, 2))
If sMode = "DEC" Then
For i = 0 To 3
arrRes(i) = Application.Hex2Dec(arrRes(i))
Next
End If
UTF16 = Join(arrRes)
End Function
【代码解析】
函数UTF16有两个参数:
使用如下过程,可以测试代码效果。
Sub InsertSymbol()
Dim moon As String, iNum
Dim arrByte(0 To 3) As Byte
iNum = Split(UTF16("1F337", "DEC"))
For i = 0 To 3
arrByte(i) = iNum(i)
Next
moon = arrByte
ActiveCell.FormulaR1C1 = moon
End Sub
【代码解析】
第4行代码指定插入字符代码为0x1F337,输出格式为十进制。
第5~7行代码将结果赋值给Byte数组。
第8行代码将Byte数组转换为字符。
第9行代码将特殊字符插入活动单元格中,效果如下图所示。
至此,字符代码和Byte数组的对应转换关系已经全部讲完了,如果对于进制转换和内存Bit位不太理解的话,可能理解起来有些困难,但是主要学会使用上面两段代码将可以了,插入特殊字符从此不用再求人!
相关链接: