¿Por qué anidar algunos comandos xstring provoca errores?

¿Por qué anidar algunos comandos xstring provoca errores?

¿Por qué combinar algún comando delpaquete xstringcausa errores? por ejemplo, cuando compilo el siguiente MWE:

\documentclass{article}
\usepackage{xstring}
\begin{document}
\section{A}
    \StrCompare{\StrChar{bbbb}{4}}{\StrChar{aaaa}{3}}% are 4th character of first argument with 3th character of second argument differ ---> result 1 (yes and in first position)
\end{document}

devuelve el error:

! Undefined control sequence.
\xs_StrChar__ ...ef \xs_arg_ii {#2}\edef \xs_call 
                                                  {\noexpand \xs_testopt {\n...
l.5 ...mpare{\StrChar{bbbb}{4}}{\StrChar{aaaa}{3}}
                                                  % are 4th character of fir...

?

Respuesta1

Este es un problema bastante común xstringporque (la mayoría de) sus comandos no funcionan en contextos de solo expansión (dentro de \edefo \expandedo \writeo...), por lo que cada comando debe ejecutarse por completo antes de que comience el siguiente. En resumen, no se pueden anidar. Un ejemplo más sencillo que mostraría el mismo problema sería definir:

\newcommand\ifequal[2]{%
  \def\tempa{#1}%
  \def\tempb{#2}
  \ifx\tempa\tempb
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}

y luego use el comando dentro de un \edef:

\edef\test{\ifequal{abc}{abc}{true}{false}}

lo que arrojaría el error:

! Undefined control sequence.
\ifequal #1#2->\def \tempa 
                           {#1}\def \tempb {#2} \ifx \tempa \tempb \expandaf...
l.13 \edef\test{\ifequal{abc}{abc}
                                  {true}{false}}
?

sin embargo, si lo usaras fuera, \edeffuncionaría.

Para permitir el uso de los resultados de un xstringcomando en otro, la mayoría de los comandos tienen un argumento opcional final, que es una macro para almacenar el resultado del procesamiento, luego debe realizar cada paso por separado y recopilar el resultado en cada paso:

\documentclass{article}
\usepackage{xstring}
\begin{document}
\section{A}
\StrChar{bbbb}{4}[\tempA]
\StrChar{aaaa}{3}[\tempB]
\StrCompare{\tempA}{\tempB}
\end{document}

Ojalá pronto termine mi versión ampliable de xstring;-)

Respuesta2

No puedes usarlo \StrCharen el argumento de \StrCompare.

Aquí hay dos implementaciones: una con xparsey expl3otra con xstring. Tenga en cuenta que el primero es completamente ampliable, el segundo no.

\documentclass{article}
\usepackage{xparse}
\usepackage{xstring} % for comparison

\ExplSyntaxOn

\NewExpandableDocumentCommand{\comparestringitems}{mmmmmm}
 {
  % #1 = first string
  % #2 = item number
  % #3 = second string
  % #4 = item number
  % #5 = true text
  % #6 = false text
  \str_if_eq:eeTF { \str_item:nn { #1 } { #2 } } { \str_item:nn { #3 } { #4 } } { #5 } { #6 }
 }

\prg_generate_conditional_variant:Nnn \str_if_eq:nn { ee } { TF,T,F,p }

\ExplSyntaxOff

\newcommand{\comparestringitemsxstring}[6]{%
  \StrChar{#1}{#2}[\compareA]%
  \StrChar{#3}{#4}[\compareB]%
  \StrCompare{\compareA}{\compareB}[\compareC]
  \ifnum\compareC=0 #5\else#6\fi
}

\begin{document}

\comparestringitems{aaaa}{4}{bbbb}{3}{true}{false}

\comparestringitems{aaaa}{4}{bbab}{3}{true}{false}

\comparestringitemsxstring{aaaa}{4}{bbbb}{3}{true}{false}

\comparestringitemsxstring{aaaa}{4}{bbab}{3}{true}{false}

\edef\test{\comparestringitems{aaaa}{4}{bbab}{3}{true}{false}}
\texttt{\meaning\test}

\end{document}

ingrese la descripción de la imagen aquí

Con una simple modificación, también puedes pasar macros a \comparestringitems:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\comparestringitems}{mmmmmm}
 {
  % #1 = first string
  % #2 = item number
  % #3 = second string
  % #4 = item number
  % #5 = true text
  % #6 = false text
  \str_if_eq:eeTF { \str_item:en { #1 } { #2 } } { \str_item:en { #3 } { #4 } } { #5 } { #6 }
 }

\prg_generate_conditional_variant:Nnn \str_if_eq:nn { ee } { TF,T,F,p }
\cs_generate_variant:Nn \str_item:nn { e }

\ExplSyntaxOff

\newcommand{\strA}{aaaa}
\newcommand{\strB}{bbbb}
\newcommand{\strC}{bbab}

\begin{document}

\comparestringitems{\strA}{4}{\strB}{3}{true}{false}

\comparestringitems{\strA}{4}{\strC}{3}{true}{false}

\edef\test{\comparestringitems{\strA}{4}{\strC}{3}{true}{false}}
\texttt{\meaning\test}

\end{document}

ingrese la descripción de la imagen aquí

información relacionada