仅当通过宏提供参数时,命令才会在需要时添加前缀单词,这存在问题

仅当通过宏提供参数时,命令才会在需要时添加前缀单词,这存在问题

考虑以下来自的代码答案,仅当前缀缺失时,它才会为单词添加前缀。

\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

在此处输入图片描述

相关内容