
考慮以下程式碼來自這答案,僅在缺少前綴時才為單字加上前綴。
\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
(expand哦nce)或e
(展開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
。