# \str_case:nnF not finding match

I have written a command using expl3 that is supposed to behave differently if the optional argument is specified as * or **. The command is intended for a math environment, and is supposed to render the second parameter with an upright underset depending on the first parameter. I see three problems in the behavior of this command:

1. The * and ** are not recognized
2. An extraneous hyphen (-) is displayed
3. An extraneous quote (") is displayed

\documentclass{article}
\usepackage{mathtools}
\usepackage{xparse}

\ExplSyntaxOn

% Render underscored with some variation of strict
\NewDocumentCommand{\strict}{O{strict} m}
{
\str_if_eq:eeTF {\str_item:nn {#1} {-1}} {-}
{
\show_strict:nn {{#1}strict} {#2}
}
{
\show_strict:nn {#1} {#2}
}
}

\cs_new_protected:Npn \show_strict:nn #1 #2
{
\msg_term:n {show_strict \ P1 \ = \ #1}
\msg_term:n {show_strict \ P2 \ = \ #2}
\str_set:Nn \l_tmpa_str {#1}
\str_set:Nn \l_tmpb_str {#2}
\msg_term:n {\l_tmpa_str =  \l_tmpa_str}
\str_case:nnF {\l_tmpa_str}
{
{
{*}
{  \underset {\mathrm{(semi-strict,strict)}} {#2} }
}
{
{**}
{ \underset {\mathrm{semi-strict (strict)}} {#2} }
}
}
{
\underset {\mathrm{\l_tmpa_str}} {\l_tmpb_str}
}
}

\ExplSyntaxOff

\begin{document}

\begin{enumerate}
\item Test $\strict{{default}}$ \\*
expect underset with upright "strict"
\item Test $\strict[semi-]{{hyphen}}$
expect underset with upright "semi-strict"
\item Test $\strict[*]{{star}}$
expect underset with upright "(semi-strict,strict)"
\item Test $\strict[**]{{starstar}}$
expect underset with upright "semi-strict (strict)"
\end{enumerate}
\foo

\end{document}

• You don't want to output \str_... variables here, that cause the - -- use \tl_... variables for the output and the \str_case:nnF is wrongly setup, in my point of view – user31729 Feb 3 '19 at 22:08
• Why not using a \NewDocumentCommand{ssO{strict}m} - approach, leaving the 'tricky' * handling to the features of xparse – user31729 Feb 3 '19 at 22:27
• Regarding your latest edit: 1) You have an extra } in the definition of \show_strict:nn. 2) It's not a good idea to edit your question asking something else, as may invalidate the answers. The best approach is to ask a new question. – Phelype Oleinik Feb 5 '19 at 21:40
• @I want * and ** as alternatives to the text string, i.e., \strict [foo]{bar}, \strict []{bar} or \strict [*]{bar}, as they all specify what to underset foo with. – shmuel Feb 5 '19 at 21:54

You have the syntax for \str_case:nnF wrong; the first argument is the string to look for matches; the second argument should be of the form

{<string-a>}{<code>}
{<string-b>}{<code>}
...


and you have additional braces that are wrong.

\documentclass{article}
\usepackage{mathtools}
\usepackage{xparse}

\ExplSyntaxOn

% Render underscored with some variation of strict
\NewDocumentCommand{\strict}{O{strict} m}
{
\str_if_eq:eeTF {\str_item:nn {#1} {-1}} {-}
{
\show_strict:nn {{#1}strict} {#2}
}
{
\show_strict:nn {#1} {#2}
}
}

\cs_new_protected:Npn \show_strict:nn #1 #2
{
\iow_term:n {show_strict ~ P1 ~ = ~ #1}
\iow_term:n {show_strict ~ P2 ~ = ~ #2}
\str_case:nnF {#1}
{
{*}  { \underset {\textup{(semi-strict,~strict)}} {#2} }
{**} { \underset {\textup{semi-strict~(strict)}} {#2} }
}
{
\underset {\textup{#1}} {#2}
}
}

\ExplSyntaxOff

\begin{document}

\begin{enumerate}
\item Test $\strict{{default}}$ \\*
expect underset with upright "strict"
\item Test $\strict[semi-]{{hyphen}}$
expect underset with upright "semi-strict"
\item Test $\strict[*]{{star}}$
expect underset with upright "(semi-strict,strict)"
\item Test $\strict[**]{{starstar}}$
expect underset with upright "semi-strict (strict)"
\end{enumerate}

\end{document}


Rather than \mathrm you should use \textup (the hyphens would be minus signs otherwise and spaces would be ignored).

Here's the console output:

*************************************************
* show_strict P1 = strict
*************************************************
*************************************************
* show_strict P2 = {default}
*************************************************
*************************************************
* show_strict P1 = {semi-}strict
*************************************************
*************************************************
* show_strict P2 = {hyphen}
*************************************************
*************************************************
* show_strict P1 = *
*************************************************
*************************************************
* show_strict P2 = {star}
*************************************************
*************************************************
* show_strict P1 = **
*************************************************
*************************************************
* show_strict P2 = {starstar}
*************************************************

• How did you avoid the "! You can't use macro parameter character #' in math mode. <recently read> ## l.42 \underset {\textup{#1}} {#2}" message? – shmuel Feb 5 '19 at 21:09
• @shmuel Do you get it with my code? I don't. – egreg Feb 5 '19 at 21:13
• @shmuel Check your braces. You have a } too much. – egreg Feb 5 '19 at 21:42
• @egreg, sorry again, you can update this response...just in order to keep the forum updated. – Pablo González L Oct 28 '19 at 22:37
• @PabloGonzálezL Thanks for the search! – egreg Oct 28 '19 at 23:01

When you do

\str_set:Nn \l_tmpa_str {#1}
\str_set:Nn \l_tmpb_str {#2}


you are setting the variables to TeX strings, removing the meaning from the tokens. In particular, { and } cease to be 'special', and come out as the 'random' quote mark/hyphen you are seeing. In your example, there's no reason to store these at all, but if you do, use a tl.

The second issue is

\str_case:nnF {\l_tmpa_str}


which compares exactly the text \l_tmpa_str with each case. They never match, so you get the F branch. You want to look at the text itself, easiest with

\str_case:nnF {#2}


or if you really want to store it, perhaps

\cs_generate_variant:Nn \str_case:nnF { V }

...

\str_case:VnF \l_tmpb_str


to access the value of the variable. Again, I suspect you want a token list test here, not a string one:

\tl_set:Nn \l_tmpb_tl {#2}
\tl_case:NnF \l_tmpb_tl
`

although as previously-mentioned, I don't see the need to store the input.