考虑以下来自的代码这答案,仅当前缀缺失时,它才会为单词添加前缀。
\documentclass[border=6pt,varwidth]{standalone}
\ExplSyntaxOn
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
{
\str_if_eq:eeTF {#2} { \str_range:nnn {#1} { 1 } { \str_count:n {#2} } }
{#1}
{ #2#1 }
}
\ExplSyntaxOff
\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}
\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}
\begin{document}
\forcebeginwith{fancycolor}{fancy} \\% OK: fancycolor
\forcebeginwith{color}{fancy} \\% OK: fancycolor
\forcebeginwith{\mystringc}{\prefixc} \\% NOT WORKING: fancyfancycolor
\end{document}
问题:鉴于我需要命令可扩展,如何使其工作?
答案1
给定一个 expl3 基函数,您可以生成一个变体,该变体在将结果传递给该函数之前处理一个或多个参数。例如,如果一个函数有一个参数说明符(冒号后面的位)n
,您可以定义一个变体,该变体具有o
(expandonce)或e
(展开埃详尽地)代替n
。然后,您只需在需要的地方使用变体即可。
在这种情况下,我们需要两个函数的变体
\cs_generate_variant:Nn \str_range:nnn { enn }
这确保\str_range:enn
存在。此变体将扩展第一个参数,然后将其交给函数\str_range:nnn
进行处理。
\cs_generate_variant:Nn \str_count:n { e }
这确保\str_count:e
存在,它在将其传递给之前扩展其唯一的参数\str_count:n
。
然后我们可以像使用基本函数一样使用这些变体
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
{
\str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
{#1}
{ #2#1 }
}
完整代码:
\documentclass[border=6pt,varwidth]{standalone}
\ExplSyntaxOn
\cs_generate_variant:Nn \str_range:nnn { enn }
\cs_generate_variant:Nn \str_count:n { e }
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
{
\str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
{#1}
{ #2#1 }
}
\ExplSyntaxOff
\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}
\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}
\begin{document}
\forcebeginwith{fancycolor}{fancy} \par% OK: fancycolor
\forcebeginwith{color}{fancy} \par% OK: fancycolor
\forcebeginwith{\mystringc}{\prefixc} \par% NOT WORKING: fancyfancycolor
\end{document}
答案2
以下是一个例子:
\documentclass[border=6pt,varwidth]{standalone}
\ExplSyntaxOn
\cs_generate_variant:Nn \str_range:nnn { enn }
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
{
\str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
{#1}
{ #2#1 }
}
\ExplSyntaxOff
\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}
\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}
\begin{document}
\forcebeginwith{fancycolor}{fancy} \\% OK: fancycolor
\forcebeginwith{color}{fancy} \\% OK: fancycolor
\forcebeginwith{\mystringc}{\prefixc} \\% NOT WORKING: fancyfancycolor
\end{document}
答案3
更好的编程风格是根据内部函数定义用户级命令。
\documentclass{article}
\ExplSyntaxOn
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
{
\vincent_forcebeginwith:ee { #1 } { #2 }
}
\cs_new:Nn \vincent_forcebeginwith:nn
{
\str_if_eq:eeF {#2} { \str_range:nnn {#1} { 1 } { \str_count:n {#2} } } { #2 }
#1
}
\cs_generate_variant:Nn \vincent_forcebeginwith:nn { ee }
\ExplSyntaxOff
\newcommand{\mystringa}{fancycolor}
\newcommand{\mystringb}{\mystringa}
\newcommand{\mystringc}{\mystringb}
\newcommand{\prefixa}{fancy}
\newcommand{\prefixb}{\prefixa}
\newcommand{\prefixc}{\prefixb}
\begin{document}
\forcebeginwith{fancycolor}{fancy} % OK: fancycolor
\forcebeginwith{color}{fancy} % OK: fancycolor
\forcebeginwith{\mystringc}{\prefixc} % OK: fancycolor
\end{document}
正如您所见,\vincent_forcebeginwith:nn
已经定义了,但在用户级命令中,我们使用了它的变体,在将其交给之前完全扩展它的参数\vincent_forcebeginwith:nn
。