1

I have the following code in my preamble:

\usepackage{xstring}
\newcommand\myhelpermacro[1]{\IfSubStr{#1}{true}{Text contained the word "cat"}{Text did not contain the word "cat"}}
\newcommand\mymacro[1]{\myhelpermacro{\IfSubStr{#1}{cat}{true}{false}}}

When I later try to use mymacro in the document, like so:

\mymacro{cat}

I get the following error:

Use of \@xs@IfSubStr@@ doesn't match its definition. \mymacro{cat}

Modifying mymacro by using \expandafter, like so:

\newcommand\mymacro[1]{\expandafter\myhelpermacro{\IfSubStr{#1}{cat}{true}{false}}}

doesn't help. However, if I instead manually expand the call to IfSubStr in mymacro, i.e.

\newcommand\mymacro[1]{\myhelpermacro{true}}

the code works.

What is going on here? Why doesn't my code work without manually expanding IfSubStr?


Edit 1: To clarify my expectations of the behavior of the code, I expect that when I use, e.g.,

\mymacro{caterpillar}

this expands to

\myhelpermacro{\IfSubStr{caterpillar}{cat}{true}{false}}

which in turn should expand (since I expect what's inside the brackets to be expanded before what's outside of them, because that's how brackets are supposed to behave, right? :) ) to

\myhelpermacro{true}

which in turn should expand to Text contained the word "cat".

However, when I use, e.g.,

\mymacro{aardvark}

I expect this to expand to

\myhelpermacro{\IfSubStr{aardvark}{cat}{true}{false}}

which in turn should expand to

\myhelpermacro{false}

which in turn should expand to Text did not contain the word "cat".


Edit 2: After reading the xstring documentation (under 3.2 Expansion of macros, optional argument), I tried changing the definition of mymacro, by storing the result of IfSubStr in a temporary variable, to

\newcommand\mymacro[1]{\IfSubStr{#1}{cat}{true}{false}[\result]\myhelpermacro{\‌​result}}

only to get the following error message when I try to use mymacro:

Undefined control sequence. \mymacro{cat}

Suddenly, LaTeX seems to think mymacro isn't defined at all. Why?


Edit 3: So what I'm trying to do is to define two macros:

The first macro (myhelpermacro in this case) that takes a boolean value and inserts a string into the document whose value depends on the value of the boolean.

The second macro (mymacro in this case) takes a string and calls the first macro with the boolean true if the string contains a specific substring, otherwise it calls the first macro with the boolean false.

Since I want to be able to make calls to both macros from the document, both of them need to be defined, and since I want to avoid code duplication, the second macro should call the first macro instead of inserting the string into the document itself.

15
  • When I look at your code, it seems that mymacro calls myhelpmacro with IfSubStr as part of the argument. But myhelpmacro already has IfSubStr in its definition. So, IfSubStr is called within itself.
    – user139954
    Aug 13, 2017 at 15:59
  • 4
    There are several questions dealing with the fact that you cannot nest xstring macros.
    – egreg
    Aug 13, 2017 at 16:10
  • @egreg Okay; why can't I do that? And how can I solve this in a different but equally powerful way in that case? I want to be able to make calls to mymacro and myhelpermacro. Aug 13, 2017 at 16:25
  • 2
    @StrawberryFieldsForever \IfSubstr{AAA}{A}{true}{false} is a set of instructions to print true, not the string true. Some context would help: this seems like an XY question.
    – egreg
    Aug 13, 2017 at 16:36
  • 1
    @erreka No, that's not the issue: it's that the implementation of \IfSubstr performs assignments, and they cannot be expanded. (This is a general feature of TeX.)
    – Joseph Wright
    Aug 14, 2017 at 19:45

1 Answer 1

1

With functional package, composition of functions works as expected if you are familiar with other programming languages such as Lua or JavaScript.

\documentclass{article}
\usepackage{functional}
\begin{document}

\IgnoreSpacesOn
\PrgNewFunction \mymacro {m} {
  \myhelpermacro{\StrIfInTF{#1}{cat}{\Result{true}}{\Result{false}}}
}
\PrgNewFunction \myhelpermacro {m} {
  \StrIfInTF {#1} {true} {
    \Result{Text ~ contained ~ the ~ word ~ "cat"}
  }{
    \Result{Text ~ did ~ not ~ contain ~ the ~ word ~ "cat"}
  }
}
\IgnoreSpacesOff

\mymacro{caterpillar}

\mymacro{butterfly}

\end{document}

enter image description here

Note that with this package, you need to pass return values of functions with \Result command.

You must log in to answer this question.

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