Problema con un comando que antepone palabras solo si es necesario cuando los argumentos se proporcionan a través de macros

Problema con un comando que antepone palabras solo si es necesario cuando los argumentos se proporcionan a través de macros

Considere el siguiente código proveniente deesterespuesta, donde agrega un prefijo a una palabra, solo si falta el prefijo.

\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}

PREGUNTA:¿Cómo hacer que funcione dado que necesito que el comando sea ampliable?

Respuesta1

Dada una función base expl3, puede generar una variante que procese uno o más argumentos antes de pasar los resultados a esa función. Por ejemplo, si una función tiene un especificador de argumento (el bit después de los dos puntos) n, puede definir una variante que tenga o(expandirohnce) o e(expandirmiexhaustivamente) en lugar de n. Luego simplemente utiliza la variante donde sea necesario.

En este caso, queremos variantes de dos funciones.

\cs_generate_variant:Nn \str_range:nnn { enn }

Esto asegura \str_range:ennque existe. Esta variante expandirá el primer argumento antes de entregárselo a la función \str_range:nnnpara su procesamiento.

\cs_generate_variant:Nn \str_count:n { e }

Esto asegura \str_count:eque existe, lo que expande su único argumento antes de pasarlo a \str_count:n.

Entonces podemos usar estas variantes tal como lo haríamos con las funciones base.

\NewExpandableDocumentCommand { \forcebeginwith } { m m }
  {
    \str_if_eq:eeTF {#2} { \str_range:enn {#1} { 1 } { \str_count:e {#2} } }
      {#1}
      { #2#1 }
  }

Las variantes expanden los argumentos antes del procesamiento para que las tres líneas den el mismo resultado.

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}

Respuesta2

Aquí hay un ejemplo:

\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}

Respuesta3

Un mejor estilo de programación es definir el comando a nivel de usuario en términos de una función 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 ves \vincent_forcebeginwith:nnestá definido, pero en el comando a nivel de usuario usamos una variante del mismo que expande completamente sus argumentos antes de entregárselos a \vincent_forcebeginwith:nn.

ingrese la descripción de la imagen aquí

información relacionada