想做一个用户自定义定理环境的接口,下面是只是 MWE ,其他功能尚未写入。本来想用 l3keys 的接口来做的。但是把 interface3 文档看来看去,都觉得 l3keys 做不到用户自定义 key 。所以就换了个思路,用字符串切割的方法模拟 l3keys 的用法。
输出效果只显示最后一个定义环境的中文名,问题不知出在哪(猜测跟 token list 的展开有关?)。期望输出效果是 definition
环境显示“定义 1. 定义测试”。
求教如何解决这个问题。如果有用 l3keys 实现的其他方法也可以。
\documentclass{ctexart}
\usepackage{amsthm}
\ExplSyntaxOn
% 使用方法 \addtheorem{<style>}{<environment name>=<Chinese name>, ...}
\NewDocumentCommand \addtheorem { m m }
{
\tl_set:Nn \l_theorem_style_tl { #1 }
\clist_map_inline:nn { #2 }
{
\seq_set_split:Nnn \l_theorem_environment_chinese_seq { = } { ##1 }
\seq_pop_left:NN \l_theorem_environment_chinese_seq \l_theorem_environment_tl
\seq_pop_left:NN \l_theorem_environment_chinese_seq \l_theorem_chinese_tl
\theoremstyle { \l_theorem_style_tl }
\newtheorem { \l_theorem_environment_tl } { \l_theorem_chinese_tl }
\newtheorem* { \l_theorem_environment_tl* } { \l_theorem_chinese_tl }
}
}
\ExplSyntaxOff
\addtheorem{definition}{
definition = 定义,
assume = 假设,
lemma = 引理,
question = 问题
}
\addtheorem{remark}{
remark = 注
}
\begin{document}
\begin{definition}
定义测试
\end{definition}
\begin{remark*}
注释测试
\end{remark*}
\end{document}
问题出在 \newtheorem
并不会展开第 2 个参数,所以保留的是 \l_theorem_chinese_tl
的最后一个定义。
这里提供使用 \keyval_parse:nnn
的方法,比用 prop 更为简洁、快速。
\ExplSyntaxOn
% 使用方法 \addtheorem{<style>}{<environment name>=<Chinese name>, <environment name>, ...}
\NewDocumentCommand \addtheorem { m m }
{
\tl_set:Nn \l_theorem_style_tl {#1}
\keyval_parse:nnn { \__theorem_new_theorem:nn { } } { \__theorem_new_theorem:nn } {#2}
}
\cs_new:Npn \__theorem_new_theorem:nn #1#2
{
\theoremstyle { \l_theorem_style_tl }
\tl_if_empty:nTF {#1}
{
\exp_last_unbraced:Ne \newtheorem { {#2} { \text_titlecase_first:n {#2} } }
\exp_last_unbraced:Ne \newtheorem { * {#2*} { \text_titlecase_first:n {#2} } }
}
{
\newtheorem {#1} {#2}
\newtheorem * {#1*} {#2}
}
}
\ExplSyntaxOff
还额外支持没有给出 <chinese name>
的情况,此时把 <environment name>
第一个字母大写作为 <chinese name>
。如果不想要这个特性,把 \tl_if_empty:nTF
的 true 分支删掉即可。
比如:
\addtheorem{definition}{
definition = 定义,
assume = 假设,
lemma = 引理,
question = 问题,
corollary
}
\addtheorem{remark}{
remark = 注
}
如果不知道某一个命令会不会展开它的参数,最好的解决办法是先展开参数(用 \exp_args:N..
或 \exp_last_unbraced:N..
),再传递给这个命令。
经群友提醒,换用 l3prop 模块能实现功能。不过仍想知道原方法失效的原因,多学习学习。
\documentclass{ctexart}
\usepackage{amsthm}
\ExplSyntaxOn
% 使用方法 \addtheorem{<style>}{<environment name>=<Chinese name>, ...}
\NewDocumentCommand \addtheorem { m m }
{
\prop_set_from_keyval:Nn \l_theorem_environment_chinese_prop { #2 }
\prop_map_inline:Nn \l_theorem_environment_chinese_prop
{
\theoremstyle { #1 }
\newtheorem { ##1 } { ##2 }
\newtheorem* { ##1* } { ##2 }
}
}
\ExplSyntaxOff
\addtheorem{definition}{
definition = 定义,
assume = 假设,
lemma = 引理,
question = 问题
}
\addtheorem{remark}{
remark = 注
}
\begin{document}
\begin{definition}
定义测试
\end{definition}
\begin{remark*}
注释测试
\end{remark*}
\end{document}