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 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.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.