Rem*_*eau 18
只需一点数学知识就可以将有效的UTF-8 字节序列直接转换为 UTF-16。
验证 UTF-8 字节序列很简单:只需检查第一个字节是否与以下模式之一匹配,并且(byte and $C0) = $80对于序列中的每个后续字节都是如此。
UTF-8 序列中的第一个字节告诉您序列中有多少个字节:
(byte1 and $80) = $00: 1 byte
(byte1 and $E0) = $C0: 2 bytes
(byte1 and $F0) = $E0: 3 bytes
(byte1 and $F8) = $F0: 4 bytes
anything else: error
Run Code Online (Sandbox Code Playgroud)
将 UTF-8 1 字节、2 字节和 3 字节序列转换为 UTF-16 有非常简单的公式,因为它们都表示下面的 Unicode 代码点U+10000,因此可以使用 UTF-16 中的原样表示一个 16 位代码单元,不需要代理,只需一些调整,例如:
1 字节:
UTF16 = UInt16(byte1 and $7F)
Run Code Online (Sandbox Code Playgroud)
2字节:
UTF16 = (UInt16(byte1 and $1F) shl 6)
or UInt16(byte2 and $3F)
Run Code Online (Sandbox Code Playgroud)
3字节:
UTF16 = (UInt16(byte1 and $0F) shl 12)
or (UInt16(byte2 and $3F) shl 6)
or UInt16(byte3 and $3F)
Run Code Online (Sandbox Code Playgroud)
另一方面,将 UTF-8 4 字节序列转换为 UTF-16 稍微复杂一些,因为它表示 Unicode 代码点或U+10000更高,因此需要使用 UTF-16 代理项,这需要一些要计算的附加数学,例如:
4字节:
CP = (UInt32(byte1 and $07) shl 18)
or (UInt32(byte2 and $3F) shl 12)
or (UInt32(byte3 and $3F) shl 6)
or UInt32(byte4 and $3F)
CP = CP - $10000
highSurrogate = $D800 + UInt16((CP shr 10) and $3FF)
lowSurrogate = $DC00 + UInt16(CP and $3FF)
UTF16 = highSurrogate, lowSurrogate
Run Code Online (Sandbox Code Playgroud)
现在,话虽如此,让我们看看你的例子:E2 82 AC
第一个字节是($E2 and $F0) = $E0,第二个字节是($82 and $C0) = $80,第三个字节是($AC and $C0) = $80,所以这确实是一个有效的 UTF-8 3 字节序列。
将这些字节值代入 3 字节公式,您将得到:
UTF16 = (UInt16($E2 and $0F) shl 12)
or (UInt16($82 and $3F) shl 6)
or UInt16($AC and $3F)
= (UInt16($02) shl 12)
or (UInt16($02) shl 6)
or UInt16($2C)
= $2000
or $80
or $2C
= $20AC
Run Code Online (Sandbox Code Playgroud)
事实上,Unicode 代码点U+20AC在 UTF-16 中编码为$20AC.