2

Why does this code output "False":

\documentclass{article}
\usepackage{stringstrings}
\usepackage{xifthen}

\begin{document} \ifthenelse{\equal{\substring{ab}{1}{1}}{a}}{True}{False} \end{document}

There are many alternative solutions to get the desired result: Test if the first character of a string is 'a', but I would like tho understand why the above code behaves this way and what would be the closest possible solution to get the desired behavior.

Jakob
  • 993
  • 1
    \equal tests the expansion of the two expressions are equal and the stringstrings functions are not expandable they make many internal assignments – David Carlisle Jul 28 '20 at 19:46

2 Answers2

2

The macro \substring does not work by pure expansion: it produces a (long) series of commands to print the requested substring.

With [q] you can make it save the result in \thestring. Well, it always does, but [q] suppresses output at the calling spot.

\documentclass{article}
\usepackage{stringstrings}
\usepackage{xifthen}

\begin{document} \substring[q]{ab}{1}{1} \ifthenelse{\equal{\thestring}{a}}{True}{False} \end{document}

This will print “True”.

I'd prefer the more powerful expl3 routine:

\documentclass{article}
\usepackage{xparse}
\usepackage{xifthen}

\ExplSyntaxOn \NewExpandableDocumentCommand{\substring}{mmm} { \tl_range:nnn { #1 } { #2 } { #3 } } \ExplSyntaxOff

\begin{document}

\ifthenelse{\equal{\substring{ab}{1}{1}}{a}}{True}{False}

\ifthenelse{\equal{\substring{abcde}{-2}{-1}}{de}}{True}{False}

\end{document}

You see that you can also extract substrings from the end. See also https://tex.stackexchange.com/a/467527/4427 for a reimplementation of \ifthenelse with expl3.

egreg
  • 1,121,712
0

If you're free to use LuaLaTeX, consider using Lua's powerful string functions, including string.sub (short for "string subset", I suppose).

For instance, the following program defines a LaTeX macro called \TestFirstChar. \TestFirstChar{ab}{a} typesets "True".

\documentclass{article}
\newcommand\TestFirstChar[2]{%
    \directlua{if (string.sub("#1",1,1)=="#2") then tex.sprint("True")
               else tex.sprint("False") 
               end}}

\begin{document} \TestFirstChar{ab}{a} \end{document}

Mico
  • 506,678