有两个问题,
\ref
不能被完全展开,因此不能用于f
、x
、e
等展开类型中,否则会出错,必须使用底层的宏来得到 ref;- 使用
\printman{ test01 }
,时,一般两侧的空格是不需要的,使用\NewDocumentCommand { >{\TrimSpaces} m }
在传参时将其去除。
改动的地方只有两个:
\makeatletter
% 棋谱输出用户接口
% #1 棋谱label
\NewDocumentCommand{\printman}{ >{\TrimSpaces} m } % 去掉两侧空格
{
\__cchess_setman_print:n { #1 }
}
\cs_set:Npn \use_i:nnnnn #1#2#3#4#5 {#1} % LaTeX3 并未定义 \use_i:nnnnn
% 棋谱输出
\cs_new:Npn \__cchess_setman_print:n #1
{
\cs_if_exist:cTF { r@#1 }
{
% 这一步是得到 ref,它保存在 \r@#1 中。\r@#1 有两项,当使用 hyperref 时,
% \r@#1 有 5 项,这里使用 \empty 统一解决
\tl_set:Nx \l_tmpa_tl
{ #1 \exp_args:NNc \exp_after:wN \use_i:nnnnn { r@ #1 } \c_empty_tl \c_empty_tl \c_empty_tl .man }
\ior_open:NnTF \g_tmpb_ior { \l_tmpa_tl }
{
\ior_str_map_inline:Nn
% \ior_map_inline:Nn
\g_tmpb_ior
{ ##1\par }
}
{ \msg_error:nnx { csv } { file-not-found } { \l_tmpa_tl } }
\iow_close:N \g_tmpa_ior
}
{ \G@refundefinedtrue }% 引用未定义
}
完整代码:
\documentclass{ctexart}
\usepackage{xparse}
%\usepackage{hyperref}
%\usepackage{nameref,cleveref}
\makeatletter
\ExplSyntaxOn
% \label命令变体
\cs_new_protected_nopar:Npn \__cchess_setman_label:n { \label }
\cs_generate_variant:Nn \__cchess_setman_label:n { x }
\cs_set:Npn \use_i:nnnnn #1#2#3#4#5 {#1}
% 是否输出棋谱
\bool_new:N \l__cchess_with_setman_bool
% 棋谱文字说明列表(如车一进二等)
\clist_new:N \l__cchess_manual_clist
% 打谱环境棋谱标签
\tl_new:N \l__cchess_setman_label_tl
\tl_new:N \l__cchess_setman_label_num_tl
% 打谱环境用计数器
\newcounter{setman}
\coffin_new:N \l__cchess_manual_coffin
% key_value选项设计
\keys_define:nn { cchess }
{
% 棋盘背景图片
label .tl_gset:N = \l__cchess_setman_label_tl ,
label .initial:n = {} ,
}
% 打谱排版环境用户接口
\NewDocumentEnvironment{ setcchessman* }{ O{} +b }
{
\group_begin:
\bool_set_true:N \l__cchess_with_setman_bool
\keys_set:nn { cchess } { #1 }
\__cchess_setcchessman_pre_setup:n { #2 }
}{
\__cchess_setcchessman_post_setup:
\group_end:
}
% 棋谱输出用户接口
% #1 棋谱label
\NewDocumentCommand{\printman}{ >{\TrimSpaces} m }
{
\__cchess_setman_print:n { #1 }
}
% 打谱环境前处理函数
% #1 打谱命令
\cs_new:Npn \__cchess_setcchessman_pre_setup:n #1
{
\hcoffin_set:Nn \l__cchess_manual_coffin
{ 这是一个棋盘 }
\clist_put_right:Nn \l__cchess_manual_clist { 车九进一 }
\clist_put_right:Nn \l__cchess_manual_clist { 马3退2 }
}
% 打谱环境后处理函数
\cs_new:Nn \__cchess_setcchessman_post_setup:
{
% 输出结果盒子容器
\coffin_typeset:Nnnnn \l__cchess_manual_coffin
{ l }{ b } { 0pt } { 0pt }
% 星号环境需要输出打谱记录
\bool_if:NT \l__cchess_with_setman_bool
{
% 递增计数器
\refstepcounter{setman}
% 设置label标签
\__cchess_setman_label:x { \l__cchess_setman_label_tl }
% 构造文件名
\iow_open:Nn \g_tmpa_iow { \l__cchess_setman_label_tl\thesetman .man }
% 遍历打谱记录列表,输出打谱记录
\bool_until_do:nn { \clist_if_empty_p:N \l__cchess_manual_clist }
{
\clist_pop:NN \l__cchess_manual_clist \l_tmpa_tl
\iow_now:Nx \g_tmpa_iow { \l_tmpa_tl }
}
\iow_close:N \g_tmpa_iow
}
}
% 棋谱输出
\cs_new:Npn \__cchess_setman_print:n #1
{
% 根据棋谱label构建文件名
% 此处无法构建文件名
\cs_if_exist:cTF { r@#1 }
{
\tl_set:Nx \l_tmpa_tl
{ #1 \exp_args:NNc \exp_after:wN \use_i:nnnnn { r@ #1 } \c_empty_tl \c_empty_tl \c_empty_tl .man }
\ior_open:NnTF \g_tmpb_ior { \l_tmpa_tl }
{
\ior_str_map_inline:Nn
% \ior_map_inline:Nn
\g_tmpb_ior
{ ##1\par }
}
{ \msg_error:nnx { csv } { file-not-found } { \l_tmpa_tl } }
\iow_close:N \g_tmpa_ior
}
{ \G@refundefinedtrue }% 引用未定义
}
% 文件不存在错误提示
\msg_new:nnn { cchess } { file-not-found } { File~`#1'~not~found. }
\ExplSyntaxOff
\begin{document}
天圆地方大战的棋谱如棋谱 \ref{test01} 所示。
\begin{setcchessman*}[label=test01]
% 打谱命令
\end{setcchessman*}
\bigskip
这是一个棋谱
\printman{ test01 }
\bigskip
\bigskip
昏天黑地大战的棋谱如棋谱 \ref{test02} 所示。
\begin{setcchessman*}[label=test02]
% 打谱命令
\end{setcchessman*}
\end{document}
写入临时文件时,可以在文件名前加上 \jobname
(\c_sys_jobname_str
)与其它主文件的辅助文件区分开来。
问 在Expl3中通过交叉引用`\ref{label}`编号无法生成文件名字符串?