5

I try to store the result of an xstring pagckage’s command in another command (or variable, I don’t care), to reuse it in another xstring’s command, as you can see in the following MWE:

\documentclass{article}
\usepackage{xstring}

\begin{document}

%extract the first letter of the string “Abbbbbbb” and store it on the command “\temp”
\newcommand\temp{\StrChar{Abbbbbbb}{1}}

% Printing the contente of the command “\temp”, normaly it should be “A”
\temp

% Test if the content of the command “\temp” is “A”
\IfStrEq{\temp}{A}{True}{False}
\end{document}

When I compile it, I get the following message

! TeX capacity exceeded, sorry [parameter stack size=10000].
\@xs@IfStrEq@@ #1#2->
                     \@xs@assign \@xs@arg@i {#1}\@xs@assign \@xs@arg@ii {#2}...
l.9 \IfStrEq{\temp}{A}
                      {True}{False}
No pages of output.
Transcript written on test.log.

I also try to store the \StrChar output in a variable instead of command, unfortunately I have the same behavior at the compilation as you can see in this second MWE:

\documentclass{article}
\usepackage{xstring}

\begin{document}

%extract the first letter of the string “Abbbbbbb” and store it on the variable “\temp”
\def\temp{\StrChar{Abbbbbbb}{1}} % ← It’s only this line who is different from the first MWE

% Printing the contente of the command “\temp”, normaly it should be “A”
\temp

% Test if the content of the command “\temp” is “A”
\IfStrEq{\temp}{A}{True}{False}
\end{document}

And I have the same compilation error output.

I think that \StrChar produce in his output some formating not-visible commands which disturb \IfStrEq. And It would be probably needed to erase this formating not-visible commands before the \IfStrEq proceeding. But it’s just an hypothesis.

So how can I store an \StrChar output by a way witch can allow me to use this output as in imput of another xstring’s command?

6
  • Did you see tex.stackexchange.com/questions/274479/…
    – albert
    Commented Oct 5, 2018 at 13:38
  • Don't know what your actual use case is, but if extracting the 1st token of a string is it, it is much simpler without packages: \documentclass{article} \newcommand\getfirst[1]{\getfirstaux#1\relax} \def\getfirstaux#1#2\relax{#1} \begin{document} \def\temp{\getfirst{Abbbbbbb}} \temp\par \if A\temp True\else False\fi \end{document} Commented Oct 5, 2018 at 13:40
  • @StevenB.Segletes, I don’t know if your solution is enough because here I give an example with the first character extraction. But I also need to extract the 2d, 3d… nth ones.
    – fauve
    Commented Oct 5, 2018 at 14:44
  • Yes @albert but the given solution by egreg only work for digits so it doesn’t work in my case.
    – fauve
    Commented Oct 5, 2018 at 14:46
  • Is n a fixed number known in advance, or is n the totality of the string? Also, there is the stringstrings package which can do this, though (as the author) I can say the package has other issues making it less than ideal. Commented Oct 5, 2018 at 15:05

3 Answers 3

4

Finally, I get it: to register the output of an xstring command into a variable, it’s wrong to do :

\def\temp{\StrChar{Abbbbbbb}{1}}

Instead of this, we should add the name of the variable betwean bracket after the xstring’s command, like this:

\StrChar{Abbbbbbb}{1}[\temp]

Then, we could use \temp as we want.

2

Here is a packageless approach. Note though that spaces in the input are ignored:

\documentclass{article} 
\newcounter{getcount}
\newcommand\getn[2]{\setcounter{getcount}{#2}\getnext#1\relax} 
\def\getnext#1#2\relax{%
  \addtocounter{getcount}{-1}%
  \ifnum\thegetcount=0\relax
    \def\thegotten{#1}%
    \def\next{}%
  \else%
    \def\next{\getnext#2\relax\relax}%
  \fi%
  \next%
} 
\begin{document} 
\getn{Abbbbbbb}{1}
\thegotten

\if A\thegotten True\else False\fi 


\getn{Abbebbbb}{4}
\thegotten

\if e\thegotten True\else False\fi 
\end{document}

enter image description here


An approach with stringstrings. Notice that spaces are retained in the index count.

\documentclass{article}
\usepackage{stringstrings}
\begin{document}
\substring[q]{Abbbbbbb}{1}{1}
\thestring

\if A\thestring True\else False\fi

\substring[q]{Abcde fg}{7}{7}
\thestring

\if A\thestring True\else False\fi
\end{document}

enter image description here

2

You discovered that \newcommand{\temp}{\StrChar{Abbbbbbb}{1}} *doesn't extract the first item from the given string: remember that TeX never interprets in any way the replacement text given for a \def (or \newcommand that's a wrapper around it).

Thus your next \IfStrEq{\temp}{A}{True}{False} doesn't find an A, but rather the whole set of instructions to extract an A from Abbbbbbb. This is further complicated by the fact that xstring macros perform full expansion on their arguments (unless countermanded by \noexpandarg or similar declaration, see the manual for more information).

The right way to proceed is to do

\StrChar{Abbbbbbb}{1}[\temp]

(with the risk of silently overwriting the macro given last, be careful with the names.

You can avoid this by using expl3.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\tldefine}{mm}
 {
  \tl_clear_new:N #1
  \tl_set:Nf #1 { #2 }
 }

\NewExpandableDocumentCommand{\tlitem}{smm}
 {
  \IfBooleanTF { #1 }
   { \tl_item:Nn #2 { #3 } }
   { \tl_item:nn { #2 } { #3 } }
 }

\NewExpandableDocumentCommand{\tlifeq}{mmmm}
 {
  \str_if_eq:eeTF { #1 } { #2 } { #3 } { #4 }
 }

\ExplSyntaxOff

\begin{document}

\tldefine\temp{\tlitem{Abbbbbbb}{1}}

\temp

\tlifeq{\temp}{A}{True}{False}

\end{document}

Use \tlitem* if the first argument is a command which you want to expand.

This prints

A
True

The second argument to \tlitem can be a negative number, which means counting from the end.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .