如何在 Latex 中获取中文字符的 UTF-16 代码?例如,如果我想在 Latex 中打印“你”的 Unicode,如何通过让 Latex 帮我搜索代码来实现?
答案1
这是一个允许打印 Unicode 代码点、UTF8 表示和 UTF16 表示的实现。
\documentclass{article}
\usepackage{xparse}
\usepackage{fontspec}
\setmainfont{Heiti SC}
\ExplSyntaxOn
\NewDocumentCommand{\codepoint}{m}
{
U+\xiang_codepoint:n { #1 }
}
\NewDocumentCommand{\codepointutfviii}{m}
{
UTF8:\nobreakspace
\xiang_codepoint_utfviii:f { \char_codepoint_to_bytes:n { `#1 } }
}
\NewDocumentCommand{\codepointutfxvi}{m}
{
UTF16:\nobreakspace
\xiang_codepoint_utfxvi:n { #1 }
}
\NewDocumentCommand{\chardetails}{m}
{
#1~\texttt
{
\codepoint{#1},~
\codepointutfviii{#1},~
\codepointutfxvi{#1}
}
}
\cs_new:Nn \xiang_codepoint:n
{
\int_compare:nT { `#1 < 4096 } { 0 }
\int_compare:nT { `#1 < 256 } { 0 }
\int_to_Hex:n { `#1 }
}
\cs_new:Nn \xiang_codepoint_utfviii:n
{
\tl_map_function:nN { #1 } \__xiang_codepoint_utfviii_aux:n
}
\cs_generate_variant:Nn \xiang_codepoint_utfviii:n { f }
\cs_new:Nn \__xiang_codepoint_utfviii_aux:n
{
\tl_if_empty:nF { #1 }
{
<\int_to_Hex:n { #1 }>
}
}
\cs_new:Nn \xiang_codepoint_utfxvi:n
{
\int_compare:nTF { `#1 < 65536 }
{
<\xiang_codepoint:n { #1 }>
}
{
\__xiang_codepoint_utfxvi:n { #1 }
}
}
\cs_new:Nn \__xiang_codepoint_utfxvi:n
{
<
\int_to_Hex:n
{
\int_div_truncate:nn { `#1 - "10000 } { "400 } + "D800
}
>
<
\int_to_Hex:n
{
\int_mod:nn { `#1 - "10000 } { "400 } + "DC00
}
>
}
\ExplSyntaxOff
\begin{document}
\chardetails{a}
\chardetails{à}
\chardetails{。}
\chardetails{豈}
\chardetails{你}
\chardetails{
答案2
这是 中的一个实现expl3
。请参阅注释以了解其工作原理。
更新可与所有 TeX 引擎配合使用。(字符本身只能用 Unicode 引擎打印。)
我不知道这是否是最好的方法……
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\int_new:N \l__xiang_high_int
\int_new:N \l__xiang_low_int
\int_new:N \g__xiang_codepoint_int
\int_new:N \g__xiang_utfviii_byte_int
\intarray_new:Nn \g__xiang_utfviii_bytes_intarray { 4 }
\tl_new:N \l__xiang_bin_tl
\tl_new:N \l__xiang_high_tl
\tl_new:N \l__xiang_low_tl
\tl_new:N \l__xiang_byte_i_str
\tl_new:N \l__xiang_byte_ii_str
\tl_new:N \l__xiang_byte_iii_str
\tl_new:N \l__xiang_byte_iv_str
\cs_new:Nn \__xiang_utf_viii_char_to_codepoint:n
{
\int_set:Nn \g__xiang_codepoint_int { 0 }
\int_set:Nn \g__xiang_utfviii_byte_int { 0 }
\exp_args:NNx \str_set:Nn \l_tmpa_str { \tl_to_str:n { #1 } }
% add each byte from UTF-8 character to array
\str_map_inline:Nn \l_tmpa_str
{
\int_incr:N \g__xiang_utfviii_byte_int
\intarray_gset:Nnn \g__xiang_utfviii_bytes_intarray
{ \g__xiang_utfviii_byte_int } { `##1 }
}
% calculate code point from UTF-8 bytes
\int_case:nn { \g__xiang_utfviii_byte_int }
{
{ 1 }
{
\int_set:Nn \g__xiang_codepoint_int
{ \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 1 } }
}
{ 2 }
{
\int_set:Nn \g__xiang_codepoint_int
{
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 1 } - "C0 )
* "40 +
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 2 } - "80 )
}
}
{ 3 }
{
\int_set:Nn \g__xiang_codepoint_int
{
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 1 } - "E0 )
* "1000 +
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 2 } - "80 )
* "40 +
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 3 } - "80 )
}
}
{ 4 }
{
\int_set:Nn \g__xiang_codepoint_int
{
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 1 } - "F0 )
* "40000 +
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 2 } - "80 )
* "1000 +
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 3 } - "80 )
* "40 +
( \intarray_item:Nn \g__xiang_utfviii_bytes_intarray { 4 } - "80 )
}
}
}
}
\cs_new:Nn \__xiang_codepoint_to_utf_xvi:n
{
\int_compare:nTF
{ #1 < 55296 }
{
% code point between U+0000 and U+D7FF
% convert to hex
\exp_args:NNx \tl_set:Nn \l_tmpa_tl { \int_to_Hex:n {#1} }
% pad to 4 places
\int_while_do:nn
{ \tl_count:N \l_tmpa_tl < 4 }
{ \tl_put_left:Nn \l_tmpa_tl { 0 } }
% output UTF-16 in hex
0x \tl_use:N \l_tmpa_tl
}
{
\int_compare:nTF
{ 57344 <= #1 <= 65535 }
{
% code point between U+E000 and U+FFFF
% output UTF-16 in hex
0x \int_to_Hex:n {#1}
}
{
\int_compare:nTF
{ #1 > 65535 }
{
% code point between U+010000 and U+10FFFF
% subtract 0x10000
\int_set:Nn \l_tmpb_int { #1 - 65536 }
% convert to binary
\exp_args:NNx \tl_set:Nn \l__xiang_bin_tl
{
\int_to_bin:n { \l_tmpb_int }
}
% pad to 20 bits
\int_while_do:nn
{ \tl_count:N \l__xiang_bin_tl < 20 }
{
\tl_put_left:Nn \l__xiang_bin_tl { 0 }
}
% get high 10 bits
\tl_set:Nn \l__xiang_high_tl
{
\tl_range:Nnn \l__xiang_bin_tl { 1 } { 10 }
}
% get low 10 bits
\tl_set:Nn \l__xiang_low_tl
{
\tl_range:Nnn \l__xiang_bin_tl { 11 } { 20 }
}
% convert high 10 bits back to integer and add 0xD800
\int_set:Nn \l__xiang_high_int
{
55296 + \exp_args:Ne \int_from_bin:n { \l__xiang_high_tl }
}
% convert low 10 bits back to integer and add 0xDC00
\int_set:Nn \l__xiang_low_int
{
56320 + \exp_args:Ne \int_from_bin:n { \l__xiang_low_tl }
}
% output UTF-16 in hex
0x \int_to_Hex:n { \l__xiang_high_int }
\space
0x \int_to_Hex:n { \l__xiang_low_int }
}
{
% code point between U+D800 and U+DFFF
Invalid~code~point.
}
}
}
}
\NewDocumentCommand \chardetails { m }
{
\sys_if_engine_pdftex:TF
{
\__xiang_utf_viii_char_to_codepoint:n { #1 }
}
{
{ \Large #1 \par }
\int_set:Nn \g__xiang_codepoint_int { `#1 }
}
Code~point:~ \int_use:N \g__xiang_codepoint_int \par
UTF-16:~ \__xiang_codepoint_to_utf_xvi:n { \g__xiang_codepoint_int }
}
\sys_if_engine_pdftex:F
{
\usepackage{fontspec}
\setmainfont{Noto~Sans~CJK~SC}
}
\ExplSyntaxOff
\begin{document}
\chardetails{a}
\chardetails{à}
\chardetails{。}
\chardetails{豈}
\chardetails{你}
\chardetails{