我正在翻译包含大量中文名称的古文。我希望有一种方法可以让我简单地输入中文字符,以便它们自动翻译成拼音(这样就不会显示中文字符,中文字符在我的文档中以并行文本显示)。这样做的原因是它不仅可以省去很多工作(查找正确的拼音并输入),还可以避免很多意外错误。
因此,我希望使用类似 \pyc{诸葛 亮} 的命令,在输出中用“Zhūgě Liàng”替换此单词。(最好选择保留空格并将单词大写。)
xpinyin 包具有使用拼音注释汉字的所有机制,但是输出不灵活。
或者有没有其他可以做类似事情的软件包?
答案1
我想到了一个临时解决方案。主要缺点是标点符号时空格的处理。如您所见,到目前为止,示例中尚未添加任何标点符号。
\documentclass{article}
\usepackage{xpinyin}
\usepackage{fontspec}
\usepackage{expl3}
\ExplSyntaxOn
\tl_new:N \l_doc_tmpa_tl
\tl_new:N \l_doc_tmpb_tl
\tl_new:N \l_doc_tmpc_tl
\tl_new:N \l_doc_tmpd_tl
\tl_new:N \l_doc_tmpe_tl
\cs_set:Npn \__doc_group_helper:n #1 {
{\exp_not:n {#1}}
}
\newcommand{\pyonly}[1]{
\tl_set:Nn \l_doc_tmpa_tl {#1}
\tl_clear:N \l_doc_tmpd_tl
\bool_do_until:nn {\tl_if_empty_p:N \l_doc_tmpa_tl} {
\exp_args:NV \tl_if_head_is_group:nTF \l_doc_tmpa_tl {
\tl_set:Nx \l_doc_tmpb_tl {\tl_head:N \l_doc_tmpa_tl}
\tl_set:Nx \l_doc_tmpa_tl {\tl_tail:N \l_doc_tmpa_tl}
\tl_put_right:Nx \l_doc_tmpd_tl {
\exp_args:NV \__doc_group_helper:n \l_doc_tmpb_tl
}
} {
\tl_set:Nx \l_doc_tmpb_tl {\tl_head:N \l_doc_tmpa_tl}
\tl_set:Nx \l_doc_tmpa_tl {\tl_tail:N \l_doc_tmpa_tl}
\bool_if:nTF {
\bool_lazy_any_p:n {
{\exp_args:NV \token_if_letter_p:N \l_doc_tmpb_tl}
{\exp_args:NV \token_if_other_p:N \l_doc_tmpb_tl}
}
} {
\tl_set:Nx \l_doc_tmpc_tl { \exp_args:NV \__xpinyin_to_unicode:n \l_doc_tmpb_tl }
\cs_if_exist:cTF { c__xpinyin_ \l_doc_tmpc_tl _tl }{
\tl_put_right:Nx \l_doc_tmpd_tl {\tl_use:c {c__xpinyin_ \l_doc_tmpc_tl _tl}~}
} {
\tl_put_right:NV \l_doc_tmpd_tl \l_doc_tmpb_tl
}
} {
\tl_put_right:NV \l_doc_tmpd_tl \l_doc_tmpb_tl
}
}
}
\tl_show:N \l_doc_tmpd_tl
\tl_use:N \l_doc_tmpd_tl
}
\newcommand{\pyor}[2]{
\pinyin{#2}~
}
\ExplSyntaxOff
\begin{document}
\par \pyonly{你好我的名字是小明}
\par \pyonly{我的读音不\pyor{一}{er4}样}
\end{document}
这个问题在 LuaTeX 中有更好的解决方案。用纯 LaTeX 实现实在是太困难了。请参阅下面的代码。要运行它,您需要下载中文转拼音并将其保存在您的工作目录中。
\documentclass{article}
\usepackage[fontset=fandol]{ctex}
\usepackage{luacode}
\usepackage{xcolor}
\usepackage{xparse}
\begin{luacode*}
require"chn-to-pinyin"
pinyin_vowel_v_mapping = {
"ü", "Ü"
}
pinyin_vowel_tone_mapping = {
["a"] = {
"ā", "á", "ǎ", "à"
},
["e"] = {
"ē", "é", "ě", "è"
},
["i"] = {
"ī", "í", "ǐ", "ì"
},
["o"] = {
"ō", "ó", "ǒ", "ò"
},
["u"] = {
"ū", "ú", "ǔ", "ù"
},
["v"] = {
"ǖ", "ǘ", "ǚ", "ǜ"
},
["A"] = {
"Ā", "Á", "Ǎ", "À"
},
["E"] = {
"Ē", "É", "Ě", "È"
},
["I"] = {
"Ī", "Í", "Ǐ", "Ì"
},
["O"] = {
"Ō", "Ó", "Ǒ", "Ò"
},
["U"] = {
"Ū", "Ú", "Ǔ", "Ù"
},
["V"] = {
"Ǖ", "Ǘ", "Ǚ", "Ǜ"
}
}
pinyin_vowel_letters_lower = {"a", "e", "i", "o", "u", "v"}
pinyin_vowel_to_lower = {}
pinyin_vowel_to_upper = {}
for ind, lower in ipairs(pinyin_vowel_letters_lower) do
local upper = lower:upper()
local tbl1 = pinyin_vowel_tone_mapping[lower]
local tbl2 = pinyin_vowel_tone_mapping[upper]
assert(#tbl1 == #tbl2, "inconsistent pinyin configuration")
for i=1,#tbl1 do
pinyin_vowel_to_lower[tbl2[i]] = tbl1[i]
pinyin_vowel_to_upper[tbl1[i]] = tbl2[i]
end
end
pinyin_vowel_to_upper[pinyin_vowel_v_mapping[1]] = pinyin_vowel_v_mapping[2]
pinyin_vowel_to_lower[pinyin_vowel_v_mapping[2]] = pinyin_vowel_v_mapping[1]
pinyin_consonants = {
"zh", "ch", "sh", "b", "p", "m", "f", "d",
"t", "n", "l", "g", "k", "h", "j", "q", "x",
"r", "z", "c", "s", "w", "y"
}
pinyin_vowels = {
"iang", "uang", "ueng", "iong", "uai", "uei", "iao", "ian",
"uan", "van", "ang", "eng", "ing", "ong", "ia", "ua", "uo",
"ie", "ve", "ai", "ei", "ao", "ou", "iu", "an", "en", "in",
"un", "vn", "er", "i", "u", "v", "a", "o", "e"
}
pinyin_vowel_tone_locs = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
}
assert(#pinyin_vowels == #pinyin_vowel_tone_locs, "inconsistent pinyin configuration")
function find_next_consonant(s, s_lower, loc)
local b
for _, consonant in ipairs(pinyin_consonants) do
b, _ = s_lower:find(consonant, loc)
if b == loc then
return s:sub(loc, loc + #consonant - 1)
end
end
return nil
end
function find_next_vowel(s, s_lower, loc)
local b
for vowel_ind, vowel in ipairs(pinyin_vowels) do
b, _ = s_lower:find(vowel, loc)
if b == loc then
return s:sub(loc, loc + #vowel - 1), vowel_ind
end
end
return nil
end
function find_next_tone(s, s_lower, loc)
local char = s_lower:sub(loc, loc)
if char ~= nil and char:len() > 0 then
local byte = char:byte()
if byte >= 48 and byte <= 57 then
return char
end
end
return nil
end
function render_pinyin(consonant, vowel, vowel_ind, tone)
local res = ""
if consonant ~= nil then
res = res .. consonant
end
local tone_loc = -1
if tone ~= nil then
tone_loc = pinyin_vowel_tone_locs[vowel_ind]
end
local char, tone_char
for i=1,vowel:len() do
char = vowel:sub(i, i)
if i == tone_loc then
tone_char = pinyin_vowel_tone_mapping[char][tonumber(tone)]
assert(tone_char ~= nil, string.format("invalid tone combination: '%s', %s", vowel, tone))
res = res .. tone_char
else
-- deal with "v"
if char == "v" then
res = res .. pinyin_vowel_v_mapping[1]
elseif char == "V" then
res = res .. pinyin_vowel_v_mapping[2]
else
res = res .. char
end
end
end
return res
end
function latin_to_pinyin(s)
-- discard spaces
s = s:gsub("%s", "")
local s_lower = s:lower()
local loc = 1
local old_loc = loc
local consonant, vowel, tone, vowel_ind, render
local result = {}
while loc <= s:len() do
-- start by finding consonant
consonant = find_next_consonant(s, s_lower, loc)
if consonant ~= nil then
loc = loc + consonant:len()
end
-- proceed to find vowel
vowel, vowel_ind = find_next_vowel(s, s_lower, loc)
assert(vowel ~= nil, string.format("cannot find vowel for '%s...'", s:sub(loc, loc + 10)))
loc = loc + vowel:len()
-- peek next char to see if we can find a tone
tone = find_next_tone(s, s_lower, loc)
if tone ~= nil then
loc = loc + tone:len()
end
if loc == old_loc then
error("latin to pinyin algorithm is stuck, please check the integrity of latin input")
end
texio.write_nl(string.format("pinyin-debug: %s, %s, %s", consonant, vowel, tone))
render = render_pinyin(consonant, vowel, vowel_ind, tone)
table.insert(result, render)
old_loc = loc
end
return result
end
function chinese_to_pinyin(s)
local code = utf8.codepoint(s)
local char = utf8.char(code)
local pinyin = chn_to_pinyin[char]
return char, pinyin
end
function pinyin_upper(s)
cap_first = cap_first or false
local res = ""
local query, char
for p, code in utf8.codes(s) do
char = utf8.char(code)
query = pinyin_vowel_to_upper[char]
if query ~= nil then
res = res .. query
else
res = res .. char:upper()
end
end
return res
end
function chinese_to_pinyin_latex(s, cap_first)
cap_first = cap_first or false
local char, pinyin = chinese_to_pinyin(s)
local out_val = ""
if pinyin==nil then
-- special treatment for "*"
if char == "*" then
out_val = char
else
out_val = [[\textcolor{red}{]] .. char .. "}"
end
else
if cap_first then
local first_code = utf8.codepoint(pinyin)
local first_code_offset = utf8.offset(pinyin, 2)
pinyin = pinyin_upper(utf8.char(first_code)) .. pinyin:sub(first_code_offset)
end
out_val = pinyin
end
token.set_macro("l_doc_tmpc_tl", out_val)
end
\end{luacode*}
\newcommand{\latintopinyin}[1]{%
\directlua{
local pinyin_table = latin_to_pinyin("\luaescapestring{#1}")
tex.print(table.concat(pinyin_table, " "))
}%
}
\ExplSyntaxOn
\tl_new:N \l_doc_tmpa_tl
\tl_new:N \l_doc_tmpb_tl
\tl_new:N \l_doc_tmpc_tl
\NewDocumentCommand{\chntopinyin}{sm}{
\group_begin:
\tl_set:Nn \l_doc_tmpa_tl {#2}
\tl_clear:N \l_doc_tmpb_tl
\bool_do_until:nn {\tl_if_empty_p:N \l_doc_tmpa_tl} {
\exp_args:NV \tl_if_head_is_group:nTF \l_doc_tmpa_tl {
\tl_put_right:Nx \l_doc_tmpb_tl {{\tl_head:N \l_doc_tmpa_tl}}
} {
\exp_args:Nx \token_if_cs:NTF {\tl_head:N \l_doc_tmpa_tl} {
\tl_put_right:Nx \l_doc_tmpb_tl {\tl_head:N \l_doc_tmpa_tl}
} {
\IfBooleanTF{#1}{
\directlua{
chinese_to_pinyin_latex("\luaescapestring{\tl_head:N\l_doc_tmpa_tl}", true)
}
\tl_put_right:NV \l_doc_tmpb_tl \l_doc_tmpc_tl
}{
\directlua{
chinese_to_pinyin_latex("\luaescapestring{\tl_head:N\l_doc_tmpa_tl}")
}
\tl_put_right:NV \l_doc_tmpb_tl \l_doc_tmpc_tl
}
\tl_put_right:NV \l_doc_tmpb_tl \space
}
}
\tl_set:Nx \l_doc_tmpa_tl {\tl_tail:N \l_doc_tmpa_tl}
}
\tl_use:N \l_doc_tmpb_tl
\group_end:
}
\newcommand{\pinyin}[2]{
\latintopinyin{#2}\space
}
\ExplSyntaxOff
\begin{document}
\par\latintopinyin{zhuang1jia1huan2chuang4}
\par\latintopinyin{yi1Er2SAn1SI4}
\par Supported characters are highlighted in red
\par\chntopinyin{测试\chntopinyin*{中文}到\pinyin{拼}{pin3}音\pinyin{转}{Zhuan3}换ひらがな}
\par\chntopinyin{\chntopinyin*{诸葛亮}六出祁山}
\par\chntopinyin*{二}
\end{document}
答案2
问题涉及多个方面:(1)打印拼音;(2)格式化名称;(3)处理空格。
这里讨论第一个方面,直接演示如何读取拼音数据库,并定义一个命令来使用 expl3 函数replace
将每个字符替换为其拼音,打印单读拼音和多个读音中的第一个(标有 *)或多个读音的全集(括在括号中)
因此:
如果事先知道名称,并且用空格格式化,则可以对其进行拼音(先读)和标题大小写:
暗示在有多种可能的读数的情况下需要标记。
平均能量损失
代码可以在 lualatex 下运行。仅使用 expl3。不依赖 xpinyin 包(它通过 xeCJK 依赖项与 xelatex 绑定)。
\documentclass{article}
\usepackage{fontspec}
\setmainfont{Noto Serif}
\setsansfont{Noto Sans}
\setmonofont{Noto Sans Mono}
\usepackage{xparse}
\newfontfamily\cjk{NotoSerifCJKtc-Regular}
%-------------------------------------------------------------
\ExplSyntaxOn
% Adapted from xpinyin.sty:
% #1 (character), rather than #2 (Unicode codepoint),
% becomes part of the control sequence name.
% #3 is the pinyin. All three are in the database.
\cs_new_protected:Npn \xpinyin_customary:nnn #1#2
{ \cs_gset_nopar:cpn { c__xpinyin_#1_tl } }
\cs_new_protected:Npn \xpinyin_multiple:nnn #1#2
{ \cs_gset_nopar:cpn { c__xpinyin_multiple_#1_clist } }
\group_begin:
\cs_set_eq:NN \XPYU \xpinyin_customary:nnn
\cs_set_eq:NN \XPYUM \xpinyin_multiple:nnn
\file_input:n { xpinyin-database.def }
\group_end:
\cs_generate_variant:Nn
\tl_replace_all:Nnn
{ Nxx }
\cs_generate_variant:Nn
\str_replace_all:Nnn
{ Nxx }
%-----------------------------
\cs_set:Npn \gl_funcxpp:n #1 {
\tl_set:Nn \l_tmpb_tl { #1 }
% \tl_show:N \l_tmpb_tl
\tl_replace_all:Nxx
\l_tmpa_tl
{ \l_tmpb_tl }
{
\clist_if_exist:cTF
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ % there is a comma list for the character
\bool_if:NTF
\g__gloss_printfirstvar_bool
{ % bool true = print first reading
\clist_item:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ 1 }
* %=multi
}
{ % bool false = print all readings
(
\clist_use:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ , }
)
}
\tex_space:D
}
{ % not a comma list = only one reading
\cs_if_exist:cT
{ c__xpinyin_ \l_tmpb_tl _tl }
{
\use:c { c__xpinyin_ \l_tmpb_tl _tl }
\tex_space:D
}
}
}
% \cs_show:c { c__xpinyin_ \l_tmpb_tl _tl }
}
\tl_new:N \l_gl_item_tl
%-----------------------------
\cs_set:Npn \gl_functitlecase:n #1
{~
\tl_set:Nn \l_gl_item_tl { #1 }
\text_titlecase:nn {en} { \tl_use:N \l_gl_item_tl }
% \tex_space:D
}
%-----------------------------
\cs_set:Npn \gl_funcxppname:n #1 {
\tl_set:Nn \l_tmpb_tl { #1 }
\tl_replace_all:Nxx
\l_tmpa_tl
{ \l_tmpb_tl }
{
\clist_if_exist:cTF
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ % there is a comma list for the character
\clist_item:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ 1 }
}
{ % not a comma list = only one reading
\cs_if_exist:cTF
{ c__xpinyin_ \l_tmpb_tl _tl }
{
\use:c { c__xpinyin_ \l_tmpb_tl _tl }
}
{ % anything else
#1
}
}
}
}
\bool_new:N \g__gloss_printfirstvar_bool
\NewDocumentCommand \xpppinyin { s m }
{
\IfBooleanTF {#1 }
{ \bool_gset_false:N \g__gloss_printfirstvar_bool }
{ \bool_gset_true:N \g__gloss_printfirstvar_bool }
\tl_set:Nn \l_tmpa_tl { #2 }
\tl_map_function:NN
\l_tmpa_tl
\gl_funcxpp:n
\tl_use:N \l_tmpa_tl
}
\NewDocumentCommand \xppname { m }
{
\tl_set:Nn \l_tmpa_tl { #1 }
\tl_map_function:NN
\l_tmpa_tl
\gl_funcxppname:n
\seq_set_split:NnV \l_tmpa_seq { ~ } \l_tmpa_tl
\seq_map_function:NN
\l_tmpa_seq
\gl_functitlecase:n
}
\ExplSyntaxOff
\begin{document}
{\cjk 我诸葛 亮} $\mapsto$ \xpppinyin{我诸葛 亮}
{\cjk 我诸葛 亮} $\mapsto$ \xpppinyin*{我诸葛 亮}
\xppname{诸葛 亮}
\end{document}
附录
增加了一个基本的键值机制来选择我拼音钾第 3 个字符,最多 3 个字符一、二、三:
平均能量损失
\documentclass{article}
\usepackage{fontspec}
\setmainfont{Noto Serif}
\setsansfont{Noto Sans}
\setmonofont{Noto Sans Mono}
\usepackage{xparse}
\newfontfamily\cjk{NotoSerifCJKtc-Regular}
\newfontface\sym{DejaVu Sans}
\newcommand\tick{{\sym ✓}}
%-------------------------------------------------------------
\ExplSyntaxOn
% Adapted from xpinyin.sty:
% #1 (character), rather than #2 (Unicode codepoint),
% becomes part of the control sequence name.
% #3 is the pinyin. All three are in the database.
\cs_new_protected:Npn \xpinyin_customary:nnn #1#2
{ \cs_gset_nopar:cpn { c__xpinyin_#1_tl } }
\cs_new_protected:Npn \xpinyin_multiple:nnn #1#2
{ \cs_gset_nopar:cpn { c__xpinyin_multiple_#1_clist } }
\group_begin:
\cs_set_eq:NN \XPYU \xpinyin_customary:nnn
\cs_set_eq:NN \XPYUM \xpinyin_multiple:nnn
\file_input:n { xpinyin-database.def }
\group_end:
%-----------------------------
%-----------------------------
\cs_generate_variant:Nn
\tl_replace_all:Nnn
{ Nxx }
\cs_generate_variant:Nn
\str_replace_all:Nnn
{ Nxx }
\cs_generate_variant:Nn
\seq_set_split:Nnn
{ cnx }
%-----------------------------
\keys_define:nn { mpy }
{
mpya .tl_set:c = { l_mpy_char1_tl },
mpyb .tl_set:c = { l_mpy_char2_tl },
mpyc .tl_set:c = { l_mpy_char3_tl },
}
\seq_new:c { l_mpy_char1_seq }
\seq_new:c { l_mpy_char2_seq }
\seq_new:c { l_mpy_char3_seq }
\int_new:c { l_mpy_char1item_int }
\int_new:c { l_mpy_char2item_int }
\int_new:c { l_mpy_char3item_int }
\int_new:c { l_mpy_char1py_int }
\int_new:c { l_mpy_char2py_int }
\int_new:c { l_mpy_char3py_int }
%-----------------------------
\cs_set:Npn \gl_funcxpp:n #1 {
\tl_set:Nn \l_tmpb_tl { #1 }
% \tl_show:N \l_tmpb_tl
\tl_replace_all:Nxx
\l_tmpa_tl
{ \l_tmpb_tl }
{
\clist_if_exist:cTF
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ % there is a comma list for the character
\bool_if:NTF
\g__mpy_printfirstvar_bool
{ % bool true = print first reading
\clist_item:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ 1 }
* %=multi
}
{ % bool false = print all readings
(
\clist_use:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ , }
)
}
\tex_space:D
}
{ % not a comma list = only one reading
\cs_if_exist:cT
{ c__xpinyin_ \l_tmpb_tl _tl }
{
\use:c { c__xpinyin_ \l_tmpb_tl _tl }
\tex_space:D
}
}
}
% \cs_show:c { c__xpinyin_ \l_tmpb_tl _tl }
}
\tl_new:N \l_gl_item_tl
%-----------------------------
\cs_set:Npn \gl_functitlecase:n #1
{~
\tl_set:Nn \l_gl_item_tl { #1 }
\text_titlecase:nn {en} { \tl_use:N \l_gl_item_tl }
% \tex_space:D
}
%-----------------------------
\cs_set:Npn \gl_funcxppname:n #1 {
\int_gincr:c { l_mpy_char1count_int }
\tl_set:Nn \l_tmpb_tl { #1 }
\tl_replace_all:Nxx
\l_tmpa_tl
{ \l_tmpb_tl }
{
\clist_if_exist:cTF
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ % there is a comma list for the character
% nth character's mth pinyin
\int_compare:nNnTF
{ \int_use:c { l_mpy_char1count_int } }
=
{ \int_use:c { l_mpy_char2item_int } }
{
\clist_item:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ \int_use:c { l_mpy_char2py_int } }
}%%
{ %not 2
% nth character's mth pinyin
\int_compare:nNnTF
{ \int_use:c { l_mpy_char1count_int } }
=
{ \int_use:c { l_mpy_char3item_int } }
{
\clist_item:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ \int_use:c { l_mpy_char3py_int } }
}%%
{ % not 3
% nth character's mth pinyin
\int_compare:nNnTF
{ \int_use:c { l_mpy_char1count_int } }
=
{ \int_use:c { l_mpy_char1item_int } }
{
\clist_item:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ \int_use:c { l_mpy_char1py_int } }
}%%
{ % not 1, therefore 1st pinyin
\clist_item:cn
{ c__xpinyin_multiple_ \l_tmpb_tl _clist }
{ 1 }
}%false1
}%false2
}%false3
}
{ % not a comma list = only one reading
\cs_if_exist:cTF
{ c__xpinyin_ \l_tmpb_tl _tl }
{
\use:c { c__xpinyin_ \l_tmpb_tl _tl }
}
{ % anything else
#1
}
}
}
}
\bool_new:N \g__mpy_printfirstvar_bool
\NewDocumentCommand \xpppinyin { s m }
{
\IfBooleanTF {#1 }
{ \bool_gset_false:N \g__mpy_printfirstvar_bool }
{ \bool_gset_true:N \g__mpy_printfirstvar_bool }
\tl_set:Nn \l_tmpa_tl { #2 }
\tl_map_function:NN
\l_tmpa_tl
\gl_funcxpp:n
\tl_use:N \l_tmpa_tl
}
\int_new:c { l_mpy_char1count_int }
\NewDocumentCommand \xppname { O{mpya={},
mpyb={},
mpyc={},} m }
{
\int_gset:cn { l_mpy_char1count_int } { 0 }
\int_gset:cn { l_mpy_char1item_int } { 0 }
\int_gset:cn { l_mpy_char2item_int } { 0 }
\int_gset:cn { l_mpy_char3item_int } { 0 }
\IfNoValueF{#1}
{
\keys_set:nn { mpy } { #1 }
}
%----- if the option has been set
\tl_if_empty:cF { l_mpy_char1_tl }
{
%----- store the record
\seq_set_split:cnx
{ l_mpy_char1_seq }
{ ; } % separator
{ \tl_use:c { l_mpy_char1_tl } }
%----- store the fields
\int_set:cn
{ l_mpy_char1item_int }
{
\seq_item:cn
{ l_mpy_char1_seq }
{ 1 } %the i-th character
}
\int_set:cn
{ l_mpy_char1py_int }
{
\seq_item:cn
{ l_mpy_char1_seq }
{ 2 } %the k-th pinyin reading
}
}%end1
%----- if the option has been set
\tl_if_empty:cF { l_mpy_char2_tl }
{
%----- store the record
\seq_set_split:cnx
{ l_mpy_char2_seq }
{ ; } % separator
{ \tl_use:c { l_mpy_char2_tl } }
%----- store the fields
\int_set:cn
{ l_mpy_char2item_int }
{
\seq_item:cn
{ l_mpy_char2_seq }
{ 1 } %the i-th character
}
\int_set:cn
{ l_mpy_char2py_int }
{
\seq_item:cn
{ l_mpy_char2_seq }
{ 2 } %the k-th pinyin reading
}
}%end2
%----- if the option has been set
\tl_if_empty:cF { l_mpy_char3_tl }
{
%----- store the record
\seq_set_split:cnx
{ l_mpy_char3_seq }
{ ; } % separator
{ \tl_use:c { l_mpy_char3_tl } }
%----- store the fields
\int_set:cn
{ l_mpy_char3item_int }
{
\seq_item:cn
{ l_mpy_char3_seq }
{ 1 } %the i-th character
}
\int_set:cn
{ l_mpy_char3py_int }
{
\seq_item:cn
{ l_mpy_char3_seq }
{ 2 } %the k-th pinyin reading
}
}%end3
%-----
\tl_set:Nn \l_tmpa_tl { #2 }
\tl_map_function:NN
\l_tmpa_tl
\gl_funcxppname:n
\seq_set_split:NnV \l_tmpa_seq { ~ } \l_tmpa_tl
\seq_map_function:NN
\l_tmpa_seq
\gl_functitlecase:n
}
\ExplSyntaxOff
\begin{document}
{\cjk 诸葛 亮} $\mapsto$ \xpppinyin{诸葛 亮}
{\cjk 诸葛 亮} $\mapsto$ \xpppinyin*{诸葛 亮}
\xppname{诸葛 亮}, ...
% mpya - for a character setting ``a''
% = - set it to
% 2 - character position in the argument
% ; - delimiter
% 2 - pinyin position in the comma list
\xppname[mpya=2;2]{诸葛 亮}, ...
\bigskip
\xpppinyin*{