3

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
5

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}

enter image description here

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}
*************************************************
| improve this answer | |
  • 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
3

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.

| improve this answer | |

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.