最近在完善基于xpinyin拼音宏包的汉字读写练习宏包hanzibox,想通过对xpinyin宏包得到的拼音字符串分解后参考工作室的基于xpinyin宏包获取汉字的声母,韵母,声调分离拼音声母和韵母。同时,参考stone-zeng在xpinyin:包功能的模块化中给出的示例,用LaTeX3编写了如下代码:
\documentclass{ctexart}
\usepackage{xpinyin}
\ExplSyntaxOn
\NewDocumentCommand{\splitautopy}{}
{
\group_begin:
\tl_gset_eq:Nc \l_pinyin_tl
{
c__xpinyin_ \int_to_arabic:n { `好 } _tl
}
\__split_pinyin:V \l_pinyin_tl
\group_end:
}
\NewDocumentCommand{\splitmanulpy}{}
{
\group_begin:
\tl_gset:Nx \l_pinyin_tl
{
\pinyin{hao3}
}
\__split_pinyin:V \l_pinyin_tl
\group_end:
}
\tl_new:N \l_pinyin_tl
\tl_new:N \l_test_pinyin_tl
\str_new:N \l_pinyin_str
\cs_new_protected:Npn \__split_pinyin:n #1
{
\str_clear:N \l_pinyin_str
\tl_clear:N \l_test_pinyin_tl
\tl_set:Nn \l_test_pinyin_tl {#1}
\tl_map_inline:Nn \l_test_pinyin_tl
{
\str_put_right:Nn \l_pinyin_str {##1}
}
\str_use:N \l_pinyin_str
}
\cs_generate_variant:Nn \__split_pinyin:n { V }
\cs_generate_variant:Nn \__split_pinyin:n { x }
\ExplSyntaxOff
% 正文区(有且只能有一个)
\begin{document}
\section{测试自动获取拼音}
\subsection{自动拼音}% 可以得到拼音
xpinyin宏包:\xpinyin*{好},
拼音提取:\splitautopy
\subsection{拼音调整}% 无法正确等到拼音
\setpinyin{好}{hao4}
xpinyin宏包:\xpinyin*{好},
拼音提取:\splitautopy
\section{测试手动获取拼音}% 无法得到正确的拼音
xpinyin宏包:\pinyin{hao3},
拼音提取:\splitmanulpy
\end{document}
该代码能够自动处理汉字得到的拼音,但对于使用类似\setpinyin{好}{hao4}
设置的拼音及\pinyin{hao3}
命令得到的拼音却无法正确解析(结果如图),不知哪位大神能帮我解决一下这个问题?
xpinpin
的 \setpinyin{#1}{#2}
定义是
\NewDocumentCommand \setpinyin { m m }
{
\tl_set:cn
{ c__xpinyin_ \__xpinyin_char_to_unicode:n {#1} _tl }
{ \__xpinyin_pinyin:n {#2} }
}
实际上就是把 #1
的拼音定义为了 \__xpinyin_pinyin:n {#2}
。
因此如果用户自行设置了拼音,我们只要得到 \__xpinyin_pinyin:n {#2}
中的 #2
。
如果没有自行设置,我们直接使用 \tl_use:c { c__xpinyin_ \__xpinyin_char_to_unicode:n {#1} _tl }
即可。
\documentclass{ctexart}
\usepackage{xpinyin}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_pinyin_tl
\cs_new:Npn \my_get_pinyin:n #1
{
\tl_set_eq:Nc \l_tmpa_tl { c__xpinyin_ \__xpinyin_char_to_unicode:n {#1} _tl }
\exp_args:No \tl_if_head_eq_meaning:nNTF { \l_tmpa_tl } \__xpinyin_pinyin:n
{
\tl_set:Nf \l_pinyin_tl { \exp_after:wN \use_ii:nn \l_tmpa_tl }
% 不使用 \tl_tail:N 是为了去掉括号
% \tl_set:Nf \l_pinyin_tl { \tl_tail:N \l_tmpa_tl } % \l_tmpa_tl = {...}
}
{ \tl_set_eq:NN \l_pinyin_tl \l_tmpa_tl }
}
\my_get_pinyin:n {好}
\tl_show:N \l_pinyin_tl % = hǎo
\setpinyin{好}{hao4}
\my_get_pinyin:n {好}
\tl_show:N \l_pinyin_tl % = hao4
\ExplSyntaxOff
\end{document}
代码的含义应该是十分明显的。
xpinyin
的拼音的转化、排版是由 \__xpinyin_pinyin:n
完成的,如果其参数包含数字,就将它替换为对应的声调,如果不包含数字,直接输出(当然还包括一些其它的处理)。同时它也是不可扩展的。详细可见其源码。
\pinyin
是由 \NewDocumentCommand
定义的,由它定义的命令是不可扩展的,你这里用 \tl_set:Nx
当然只能得到原本的 \pinyin{...}
。它的转化、排版也是由 \__xpinyin_pinyin:n
完成的。
不过我不懂为什么要定义 \splitmanulpy
这个命令。
如果要自动获取 \xpinyin
使用的拼音,可以定义一个新命令:
\NewDocumentCommand \myxpinyin { O{} m m } % `*' 是不必要的
{
\tl_set:Nn \l_my_curr_char_tl {#2}
\tl_set:Nn \l_pinyin_tl {#3}
\xpinyin [#1] {#2} {#3}
}
更新:
为了从 hao4
得到 hào
,只要再将其转化一次,这个功能由 \my_get_pinyin_tone:n
完成。见代码
\documentclass{ctexart}
\usepackage{xpinyin}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l__my_save_tl
\tl_new:N \l_pinyin_tl
\tl_new:N \l__my_pinyin_tl
\clist_const:Nn \c__my_tone_a_clist { a,ā,á,ǎ,à }
\clist_const:Nn \c__my_tone_o_clist { o,ō,ó,ǒ,ò }
\clist_const:Nn \c__my_tone_e_clist { e,ē,é,ě,è }
\clist_const:Nn \c__my_tone_u_clist { u,ū,ú,ǔ,ù }
\clist_const:Nn \c__my_tone_i_clist { i,ī,í,ǐ,ì }
\clist_const:Nn \c__my_tone_v_clist { ü,ǖ,ǘ,ǚ,ǜ }
\cs_new_protected:Npn \__my_pinyin_aux:n #1
{
\quark_if_recursion_tail_stop_do:nn {#1}
{
\bool_if:NT \l__xpinyin_first_bool
{ \tl_set:NV \l__my_pinyin_tl \l__xpinyin_item_tl }
}
\__xpinyin_if_number:nTF {#1}
{
\bool_if:NT \l__xpinyin_first_bool
{ \bool_set_false:N \l__xpinyin_first_bool }
\tl_put_right:NV \l__my_pinyin_tl \l__xpinyin_pre_tl
\tl_put_right:Nx \l__my_pinyin_tl
{ \clist_item:cn { c__my_tone_ \l__xpinyin_tone_tl _clist } {#1+1} }
\tl_put_right:NV \l__my_pinyin_tl \l__xpinyin_post_tl
\__xpinyin_pinyin_init:
}
{
\int_compare:nNnTF
{ 0 \cs_if_exist_use:c { c__xpinyin_ \tl_to_str:N \l__xpinyin_tone_tl _tl } } >
{ 0 \cs_if_exist_use:c { c__xpinyin_ \tl_to_str:n {#1} _tl } }
{ \tl_put_right:Nn \l__xpinyin_post_tl {#1} }
{
\tl_set:Nn \l__xpinyin_tone_tl {#1}
\tl_set_eq:NN \l__xpinyin_pre_tl \l__xpinyin_item_tl
\tl_clear:N \l__xpinyin_post_tl
}
\tl_put_right:Nx \l__xpinyin_item_tl { \__xpinyin_replace_v:n {#1} }
}
\__my_pinyin_aux:n
}
\cs_new:Npn \my_get_pinyin_tone:n #1
{
\tl_clear:N \l__my_pinyin_tl
\__xpinyin_pinyin_init:
\tl_set:Nn \l__my_save_tl {#1}
\bool_set_true:N \l__xpinyin_first_bool
\__my_pinyin_aux:n #1 \q_recursion_tail \q_recursion_stop
}
\cs_new:Npn \my_get_char_pinyin:n #1
{
\tl_set_eq:Nc \l_tmpa_tl { c__xpinyin_ \__xpinyin_char_to_unicode:n {#1} _tl }
\exp_args:No \tl_if_head_eq_meaning:nNTF { \l_tmpa_tl } \__xpinyin_pinyin:n
{
% 不使用 \tl_tail:N 是为了去掉括号
% \tl_set:Nf \l_pinyin_tl { \tl_tail:N \l_tmpa_tl } % \l_tmpa_tl = {...}
% 为了得到声调, 只要再调用 \my_get_pinyin_tone:n
\exp_args:Nf \my_get_pinyin_tone:n { \exp_after:wN \use_ii:nn \l_tmpa_tl }
\tl_set_eq:NN \l_pinyin_tl \l__my_pinyin_tl
}
{ \tl_set_eq:NN \l_pinyin_tl \l_tmpa_tl }
}
\my_get_char_pinyin:n {好}
好: \l_pinyin_tl % = hǎo
\setpinyin{好}{hao4}
\my_get_char_pinyin:n {好}
好: \l_pinyin_tl % = hào
\setpinyin{男}{lan}
\my_get_char_pinyin:n {男}
男: \l_pinyin_tl % = lan
\setpinyin{女}{Lv3}
\my_get_char_pinyin:n {女}
女: \l_pinyin_tl % = Lǚ
\par
\my_get_pinyin_tone:n {hao3}
\l__my_pinyin_tl % = hǎo
\my_get_pinyin_tone:n {hào}
\l__my_pinyin_tl % = hào
\my_get_pinyin_tone:n {mei2shi4}
\l__my_pinyin_tl % = méishì
\ExplSyntaxOff
\end{document}
主要修改了 \__xpinyin_pinyin_aux:n
、\__xpinyin_pinyin:n
命令,使得它们将标点符号保存到 \l__my_pinyin_tl
中,而不是直接输出。
\c__..._clist
用于保存对应的声调,这样,使用 \clist_item:cn
就能从标声调的字母和数字得到带有声调的字母:a
,声调3
--> ǎ
。(查 表 法)
声调字母的判断使用了 \__xpinyin_pinyin_aux:n
中的判断方法。
使用 \my_get_char_pinyin:n
可以得到单个字符的拼音,它保存在 \l_pinyin_tl
中。使用 \my_get_pinyin_tone:n
可以得到带声调的拼音,它保存在 \l__my_pinyin_tl
中。因为这两个都是不可扩展的,所以必须使用一个宏来保存。
因为这个定义使用了 ǚ
、ǎ
等符号,可能无法在其它编码环境下使用,但是 XeTeX
+ UTF8
是可以的。
非常感谢你的回复,这个方法应该能够解决我的基本问题,但是我的想法是当使用了
\setpinyin{好}{hao4}
后,能够得到hào
。\splitmanulpy
的想法也就是使用了类似\pinyin{hao4}
命令后能得到hào
。如何方便,还请能够再帮我分析一下,谢谢。
已更新。
@u78 已更新。
非常感谢,晚上我抽时间测试一下,集成到hanzibox宏包里。
再次表示感谢!
没用这个方法前对于
\setpinyin
无法得到韵母的音调(尽和长):采用该方法后可以正确实现:
没用此方法前,对于手动注音,只能简单标注:
而使用该方法后,可以分字注音: