
Considere o seguinte código vindo deesseresposta, onde adiciona um prefixo a uma palavra, somente se o prefixo estiver faltando.
\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}
PERGUNTA:Como fazer funcionar visto que preciso que o comando seja expansível?
Responder1
Dada uma função base expl3, você pode gerar uma variante que processe um ou mais argumentos antes de passar os resultados para essa função. Por exemplo, se uma função tiver um especificador de argumento (o bit após os dois pontos) n
, você poderá definir uma variante que tenha o
(expandirónce) ou e
(expandirexaustivamente) no lugar de n
. Depois, basta usar a variante sempre que necessário.
Neste caso, queremos variantes de duas funções
\cs_generate_variant:Nn \str_range:nnn { enn }
Isso garante que \str_range:enn
exista. Esta variante expandirá o primeiro argumento antes de entregá-lo à função \str_range:nnn
para processamento.
\cs_generate_variant:Nn \str_count:n { e }
Isso garante \str_count:e
que existe, o que expande seu único argumento antes de passá-lo para \str_count:n
.
Então podemos usar essas variantes da mesma forma que faríamos com as funções básicas
\NewExpandableDocumentCommand { \forcebeginwith } { m m }
{
\str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
{#1}
{ #2#1 }
}
Código completo:
\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}
Responder2
Aqui está um exemplo:
\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}
Responder3
Um estilo de programação melhor é definir o comando de nível de usuário em termos de uma função interna.
\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}
Como você pode ver, \vincent_forcebeginwith:nn
está definido, mas no comando de nível de usuário usamos uma variante dele que expande totalmente seus argumentos antes de entregá-los \vincent_forcebeginwith:nn
.