2

I can't compare comma list item with string. \clist_a is a temp var.

\documentclass[12pt]{article}
\usepackage{expl3}


\begin{document}
\ExplSyntaxOn
\clist_new:N \clist_a
\keys_define:nn { mymodule }
{
    key .code:n      = {\clist_gput_right:Nn \clist_a { #1 }},
    key .default:n   = World
}
\keys_set:nn { mymodule }
{
    key = Fred, % Prints ’Hello Fred’
    key = Amy,
    key = Tom,
} 
\clist_use:Nn \clist_a {~and~}\par

%%% Example doesn't work
\str_case:nnF {\clist_item:Nn \clist_a{1}}{
    {Fred} {Fred~in~This~Clist}
}{Doesn't~Found~Fit}\par
\str_if_eq:nnTF {\clist_item:Nn \clist_a{1}}{Fred}{Equal}{Not~equal}\par

%%% working Example
\clist_if_in:NnTF \clist_a{Fred}{in}{Not~in}\par

\clist_map_inline:Nn \clist_a {
    \str_if_eq:nnTF {#1}{Amy}
        {\clist_map_break:}
        {\#1~is~#1\par}
} 
\end{document}

Output:

enter image description here

The problem is that:

  • the \str_case:nnF can't find the match string Fred
  • why do the last 2 example \clist_map_inline:Nn and \clist_if_in:NnTF work, but the first and second example doesn't work?

I read the following about the clist in interface3:

TEXhackers note: The result is returned within the \unexpanded primitive (\exp_not:n), which means that the ⟨item⟩ does not expand further when appearing in an x-type argument expansion.

I guess the reasons may be

  • catcode of the item in clist
  • something about expansion?
1
  • 2
    Why not use the provided scratch/temp variables \g_tmpa_clist and \g_tmpb_clist? Feb 22 at 16:23

3 Answers 3

5

Sorry, I won't ignore \clist_a, which is a bad name, scratch variable or not. Stick with the naming scheme.

With

\str_case:nnF {\clist_item:Nn \g_zang_temp_clist {1}}
  {
   {Fred{Fred~in~This~Clist}
  }
  {false}

you ask LaTeX to compare the literal string

\clist_item:Nn \g_zang_temp_clist {1}

(all characters with category code 12) with the string Fred. Obviously there is no match.

What you want is to expand the first argument in order to deliver the actual item stored in the clist. What is the TeXhackers note telling us? That if you have

\clist_put_right:Nn \l_tmpa_clist {\bfseries a}

and this is the first item, then when \clist_item:Nn \l_tmpa_clist {1} is subject to e-expansion (or x-expansion), the item will be returned as \bfseries a, that is, no control sequence will be further expanded.

Thus the correct way to string-compare the item in the clist with a given string is to use a suitable e variant:

\str_if_eq:eeTF {\clist_item:Nn \g_zang_temp_clist {1}}{Fred}{equal}{not~equal}

Full code

\documentclass[12pt]{article}

\ExplSyntaxOn

\clist_new:N \g_zang_temp_clist

\keys_define:nn { mymodule }
{
    key .code:n      = {\clist_gput_right:Nn \g_zang_temp_clist { #1 }},
    key .default:n   = World,
}
\keys_set:nn { mymodule }
{
    key = Fred, % Prints ’Hello Fred’
    key = Amy,
    key = Tom,
}

\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn

%%% Example works
\str_case:enF {\clist_item:Nn \g_zang_temp_clist{1}}
 {
  {Fred}{Fred~in~This~Clist}
 }
 {Doesn't~Found~Fit}

\par

\str_if_eq:eeTF {\clist_item:Nn \g_zang_temp_clist {1}}{Fred}{Equal}{Not~equal}

\ExplSyntaxOff

\end{document}

enter image description here

You find the predefined variants in interface3.pdf, but you can define your own if necessary with \cs_generate_variant:Nn.

4

All the \str_if_eq: family functions are based on \__str_if_eq:nn, which will expand to 0 as an explicit character with category 12 if the two lists match (and either -1 or 1 if they don’t).

From source3.pdf, we can find the definitions of \str_if_eq:nn and \str_if_eq:ee:

\prg_new_conditional:Npnn \str_if_eq:nn #1#2 { p , T , F , TF }
  {
    \if:w 0 \__str_if_eq:nn { \exp_not:n {#1} } { \exp_not:n {#2} }
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\prg_new_conditional:Npnn \str_if_eq:ee #1#2 { p , T , F , TF }
  {
    \if:w 0 \__str_if_eq:nn {#1} {#2}
      \prg_return_true: \else: \prg_return_false: \fi:
  }

The only difference is that \str_if_eq:nn compares two strings without expanding them. See the following test for example:

\str_set:Nn \l_tmpa_str { hello }
\str_if_eq_p:nn { hello } { \l_tmpa_str } % returns false
\str_if_eq_p:ee { hello } { \l_tmpa_str } % returns true
2

The example works with \str_case:enF and \str_if_eq:enTF. This is because \clist_item:Nn \clist_a{1} needs to be expanded first.

This is not necessary with \clist_if_in:NnTF \clist_a{Fred}{in}{Not~in} because Fred does not need to be expanded. It is also not necessary with \str_if_eq:nnTF {#1}{Amy} because #1 also does not need to be expanded.

enter image description here

\documentclass[12pt]{article}
%\usepackage{expl3}


\begin{document}
\ExplSyntaxOn
\cs_generate_variant:Nn \str_case:nnF { enF }
\cs_generate_variant:Nn \str_if_eq:nnTF { enTF }
\clist_new:N \clist_a
\keys_define:nn { mymodule }
{
    key .code:n      = {\clist_gput_right:Nn \clist_a { #1 }},
    key .default:n   = World
}
\keys_set:nn { mymodule }
{
    key = Fred, % Prints ’Hello Fred’
    key = Amy,
    key = Tom,
} 
\clist_use:Nn \clist_a {~and~}\par

%%% Example did not work, but does now
\str_case:enF {\clist_item:Nn \clist_a{1}}{
    {Fred} {Fred~in~This~Clist}
}{Doesn't~Found~Fit}\par
\str_if_eq:enTF {\clist_item:Nn \clist_a{1}}{Fred}{Equal}{Not~equal}\par

%%% working Example
\clist_if_in:NnTF \clist_a{Fred}{in}{Not~in}\par

\clist_map_inline:Nn \clist_a {
    \str_if_eq:nnTF {#1}{Amy}
        {\clist_map_break:}
        {\#1~is~#1\par}
} 
\end{document}

You must log in to answer this question.

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