I have the following code in which I try to check whether a letter exists in a string:



\str_gset:Nn \ABCstring {ABC} % Setting the test string to 'ABC'

\tl_gset:Nn \my_tl {C} % Setting the token list to the single letter 'C'

C\ in\ ABC:~
\str_if_in:NnTF \ABCstring {C}{yes!}{no!}\\ % just the letter 'C'

\textbackslash my_tl(\my_tl)\ in\ ABC:~
\str_if_in:NnTF \ABCstring {\my_tl}{yes!}{no!}\\ % the letter 'C' from the tl


It generates this output:

C in ABC: yes!

\my_tl(C) in ABC: no!

When I put just a C into the second argument of \str_if_in:NnTF, the code works as expected (yielding yes!), while the same character in a token list does not work.

The LaTeX3 documentation gives the following signature:

\str_if_in:NnTF ⟨str var⟩ {⟨token list⟩} {⟨true code⟩} {⟨false code⟩}

accompanied with the following description:

Converts the ⟨token list⟩ to a ⟨string⟩ and tests if that ⟨string⟩ is found in the content of the ⟨str var⟩.

From my understanding of the doc, both ifs above should yield yes! What is the problem?

I figured out that it works with

\cs_generate_variant:Nn \str_if_in:NnTF {NVTF}

but why is that necessary?

  • \my_tl is converted into the string \ m y _ t l May 16, 2022 at 20:35

1 Answer 1


As the documentation says, the second argument to \str_if_in:NnTF is a {⟨token list⟩}. The token list you have passed is \my_tl, which is exactly one token. It is then detokenized as we are doing a string-based comparison, and we then have the string \my_tl, which comprises six 'other' tokens'. In contrast, you want to compare to the content of \my_tl, which is the single token C (catcode 11, 'letter'). This is passed when you use V-type expansion - it passes the value stored in \my_tl. And it it that you want to compare.

You must log in to answer this question.

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