5

Why does combining some command of the xstring package causes errors? e.g. when I compile the following 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}

it return the 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...

?
1
  • 2
    Because (most) xstring's commands are not expandable, so they can't be nested. You need to do in separate steps, something like \StrChar{bbbb}{4}[\resultA], then \StrChar{aaaa}{3}[\resultB], and then \StrCompare{\resultA}{\resultB}. The application is different, but the solution is basically the same as here – Phelype Oleinik Dec 1 '19 at 15:10
4

This is a rather common problem using xstring because (most of) its commands don't work in expansion-only contexts (Inside an \edef or \expanded or \write or. . .), so each command has to execute completely before the next one starts. In short, they can't be nested. A simpler example that would show the same problem would be to define:

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

and then use the command inside an \edef:

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

which would throw the 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}}
?

however if you used it outside the \edef it would work.

To allow using the results of one xstring command in another, most of the commands have a final optional argument, which is a macro to store the result of the processing, then you need to do each step separately and collect the result at each step:

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

Hopefully soon I'll finish my expandable version of xstring ;-)

2
  • Are you Christian Tellechea? or you want to write your own package? – user108724 Dec 1 '19 at 15:36
  • @C.F.G No, I'm not Christian :-) I'm midway through writing a string manipulation package with more or less the same feature set as xstring, but with all commands expandable. – Phelype Oleinik Dec 1 '19 at 15:38
4

You can't use \StrChar in the argument of \StrCompare.

Here are two implementations: one with xparse and expl3, one with xstring. Note that the former is completely expandable, the latter isn't.

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

enter image description here

With a simple modification, you can also pass macros to \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}

enter image description here

4
  • Thanks for your answer. Both of your answers produces some errors in my machine (Texlive 2018): – user108724 Dec 2 '19 at 7:12
  • Second code error: : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq:nnTF'. : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq:nnT'. : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq:nnF'. : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq_p:nn'. : LaTeX error: "kernel/invalid-variant" Variant form 'e' invalid for base form '\str_item:nn'. line 28: Undefined control sequence. ..ringitems{\strA}{4}{\strB}{3}{true}{false} – user108724 Dec 2 '19 at 7:12
  • First Code errors: : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq:nnTF'. : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq:nnT'. : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq:nnF'. : LaTeX error: "kernel/invalid-variant" Variant form 'ee' invalid for base form '\str_if_eq_p:nn'. line 34 36 42: Undefined control sequence. – user108724 Dec 2 '19 at 7:14
  • 1
    @C.F.G Update your TeX system – egreg Dec 2 '19 at 8:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy