![¿Por qué anidar algunos comandos xstring provoca errores?](https://rvso.com/image/405343/%C2%BFPor%20qu%C3%A9%20anidar%20algunos%20comandos%20xstring%20provoca%20errores%3F.png)
¿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 xstring
porque (la mayoría de) sus comandos no funcionan en contextos de solo expansión (dentro de \edef
o \expanded
o \write
o...), 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, \edef
funcionaría.
Para permitir el uso de los resultados de un xstring
comando 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 \StrChar
en el argumento de \StrCompare
.
Aquí hay dos implementaciones: una con xparse
y expl3
otra 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}
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}