9

I would like to make a function \des{a}{b} that produces the following result:

  • \des{Q}{1} > Q_1
  • \des{Q_c}{1} > Q_{c,1}

I have tried to adapt the code in this answer but I could not figure out how to put my second argument after the comma in the subscript.

This is the code I have produced:

\NewDocumentCommand\des{mm}{\csname riccardo_des:nn\endcsname{#1}{_}{#2}}
\ExplSyntaxOn
\cs_new_protected:Npn \riccardo_des:nn #1 #2 #3
 {
  \tl_set:Nn \l_tmpa_tl { #1 }
  \tl_if_in:NnTF \l_tmpa_tl { #2 }
   { \tl_replace_all:Nnn \l_tmpa_tl { #2 } { \riccardo_dessb:n } }
   { \tl_put_right:Nn \l_tmpa_tl { \sb { #3 } } }
  \tl_use:N \l_tmpa_tl
 }
\cs_new_protected:Npn \riccardo_dessb:n #1 
 { \sb { #1 , des } }
\ExplSyntaxOff

I want to substitute ,des in the line before the last with the second argument I pass to the \des function. How can I do this?

4 Answers4

13

Here, I search the first argument for _. If not found, I use #1_{#2}. If found (breaking down #1 as #3_#4), it uses #3_{#4,#2}.

Thanks to Mico for pointing out that comma was being set in \scriptscriptstyle. EDITED to fix.

\documentclass{article}
\newcommand\des[2]{\desaux{#1}{#2}#1_\relax}
\def\desaux#1#2#3_#4\relax{%
  \ifx\relax#4\relax
    #1_{#2}
  \else
    #3_{\stripus#4,#2}
  \fi
}
\def\stripus#1_{#1}
\begin{document}
$\des{Q}{1}$

$\des{Q_c}{1}$

$Q_{c,1}$ for comparison

$\des{Q_{ab}}{c}$
\end{document}

enter image description here

SUPPLEMENT

Based on comments of the OP, it appears that he desires interaction with \mathbf under certain scenarios (when #2 is empty). and with \bar on demand. While I am not sure if this could address all the needs, such things can be done directly in the \des macro, rather than interacting with a 2nd macro.

EDITED to also handle the bolding of greek letters (amsbsy added, with use of \boldsymbol)

For example,

\documentclass{article}
\usepackage{ifthen,amsbsy}
\newcommand\des[3][]{\desaux{#2}{#3}#2_\relax{#1}}
\def\desaux#1#2#3_#4\relax#5{%
  \ifx\relax#4\relax
    \ifx\relax#2\relax
      \boldsymbol{\mathbf{#5#1}}
    \else
      #5#1_{#2}
    \fi
  \else
    \ifx\relax#2\relax
      \boldsymbol{\mathbf{#5#3_{\stripus#4}}}
    \else
      #5#3_{\stripus#4,#2}
    \fi
  \fi
}
\def\stripus#1_{#1}
\begin{document}
$\des{Q}{1}$\par
$\des{Q_c}{1}$\par
$\des{Q}{}$\par
$\des{Q_c}{}$\par
$\des[\bar]{Q}{1}$\par
$\des[\bar]{Q_c}{1}$\par
$\des[\bar]{Q}{}$\par
$\des[\bar]{Q_c}{}$

$\des{\psi}{}$\par
$\des{\psi_\alpha}{}$\par
$\des[\bar]{\psi_\alpha}{}$
\end{document}

enter image description here

  • 1
    In the typeset version of $\des{Q_c}{1}$, the comma between c and 1 seems be both too small and placed too low. Any way to fix this? – Mico Jul 31 '18 at 19:02
  • @Mico You are right. Let me work to fix. – Steven B. Segletes Jul 31 '18 at 19:10
  • Thanks for the answer. This solution fails to put the comma in this case though: \des{\mathbf{Q_c}}{1} – Simone Gaiarin Aug 01 '18 at 11:35
  • @SimoneGaiarin It is pretty obvious why it fails, because the first argument is wrapped in a \mathbf. Not saying I can account for that, but just to point me in the right direction, should the <comma> 1 be in \mathbf? – Steven B. Segletes Aug 01 '18 at 11:47
  • @SimoneGaiarin More properly, the \mathbf should be wrapped around the outside, as in \mathbf{\des{Q_{ab}}{c}} – Steven B. Segletes Aug 01 '18 at 12:02
  • I have this complicated command that return the 'quantity' #1 bold if no subscript #2 is passed or returns it non-bold with the subscript #2. Moreover #3 is another optional modifier as \bar. If my quantity #1 has a subscript I want to add the subscript #2 after a comma (and both not bold) \newcommandx{\myquantity}[4][1=, 2=, 3=]{\des{#3{\mkcomp{#1}{#2}}}{#2}} \newcommand{\mkcomp}[2]{\ifthenelse{\equal{#2}{}}{\mathbf{#1}}{#1}} – Simone Gaiarin Aug 01 '18 at 12:15
  • @SimoneGaiarin #4 appears not to be used, what is the meaning of the optional argument [1=, 2=, 3=] which makes no sense to me? Finally, what would be a typical or challenging usage example of \myquantity? – Steven B. Segletes Aug 01 '18 at 12:49
  • @SimoneGaiarin Please see my answer SUPPLEMENT to see if it can be used in lieu of your \myquantity logic. – Steven B. Segletes Aug 01 '18 at 12:57
  • @SimoneGaiarin Your question seems of XY type; you should make a new one with the full specification for the \myquantity command; I don't think that \newcommandx is the best way to go. – egreg Aug 01 '18 at 13:52
  • 1
    @StevenB.Segletes Thanks! I think that your supplement covers all my cases – Simone Gaiarin Aug 03 '18 at 06:40
  • @egreg As suggested by you I have posted this new question https://tex.stackexchange.com/q/444413/148167 – Simone Gaiarin Aug 03 '18 at 06:56
  • @StevenB.Segletes The suggested command does not work if the quantity is a command, for example \psi. Is it there a way to change your macro to do this? – Simone Gaiarin Aug 30 '18 at 15:29
  • @SimoneGaiarin Not sure what you mean. For example, using my supplemental code, $\des[\bar]{\psi_\alpha}{\delta}$ works just fine. – Steven B. Segletes Aug 30 '18 at 15:33
  • @StevenB.Segletes Sorry for expressing the problem in a terrible way. The problem is that the greek letters are not put in bold if no subscript is passed. Apparrently though it is not a problem of the macro, but the fact that greek letters require \boldsymbol instead of \mathbf. Someone suggest to use \boldsymbol{\mathbf{#1}} to solve this. – Simone Gaiarin Aug 30 '18 at 15:43
  • @SimoneGaiarin My supplement has been revised to support your request. – Steven B. Segletes Aug 30 '18 at 16:42
6

For the sake of variety, here's a LuaLaTeX-based solution. It sets up a LaTeX macro called \des, which takes two arguments and calls a Lua function called desfn which, in turn, does most of the work with the help of two Lua string functions (string.find and string.sub).

enter image description here

\documentclass{article}
\usepackage{luacode} % for "luacode" environment and "\luastring" macro
\begin{luacode}
function desfn ( u , v )
   w = u:find ( "_" )
   if w then -- found an underscore (_) char.
      tex.sprint ( u:sub(1,w-1) .. "_{" .. u:sub(w+1) .. "," .. v .. "}" )
   else
      tex.sprint ( u .. "_{" .. v .. "}" )
   end
end
\end{luacode}

%% LaTeX side code:
\newcommand\des[2]{\directlua{desfn(\luastring{#1},\luastring{#2})}}

\begin{document}
$\des{Q}{1}$ \quad $\des{Q_c}{1}$ \quad $\des{ABC_uvw}{123}$
\end{document}
Mico
  • 506,678
5

Another solution based on LuaTeX, here by directly manipulating the math noads instead of using strings. This for example allows nesting calls to \des or contruction a version \appendsub which does not need the first argument:

\documentclass{article}
\usepackage{luacode}
\begin{luacode}
local oldsub
function storesub()
  local tail = tex.nest[tex.nest.ptr].tail
  oldsub = tail and tail.sub
  if oldsub then
    tail.sub = nil
  end
end
function recoversub(sep)
  if oldsub then
    local noad = node.new'noad'
    noad.nucleus = oldsub
    node.write(noad)
    oldsub = nil
    tex.sprint(sep)
  end
end
\end{luacode}

\newcommand\appendsub[1]{\directlua{storesub()}_{\directlua{recoversub','}#1}}
\newcommand\des[2]{#1\appendsub{#2}}

\begin{document}
$\des{Q}{1}$ \quad $\des{Q_a}{1}$ \quad $\des{Q_{ab}}{123}$ \quad $\des{\des{Q}{abc}}{123}$
\end{document}

enter image description here

Mico
  • 506,678
  • 1
    +1. Just in case there's any confusion about the ability to handle nested \des cases: the strings-based solution method provided in my answer typesets $\des{\des{Q}{abc}}{123}$ (and other nested-\des cases) just fine as well. This is the case because the \luastring macro fully expands its argument. Thus, if an instance of \des is found in either argument of a \des call, it'll get expanded (and processed by desfn) before the "outer" \des gets to do its work. – Mico Jul 31 '18 at 20:35
  • For sure, it's interesting that our LuaLaTeX-based approaches can handle nested \des cases, whereas the approaches offered by @StevenB.Segletes and @egreg apparently can not. – Mico Jul 31 '18 at 20:42
  • 1
    @Mico Nice, I missed that \luastring does full expansion. I wish I could upvote your answer again :) – Marcel Krüger Jul 31 '18 at 20:52
  • I've taken the liberty of adding some code to your answer to pretty-print the Lua code block. Feel free to revert if you don't like the result. – Mico Jul 31 '18 at 21:01
3

You can exploit regular expressions:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\des}{mm}
 {
  \simone_des:nn { #1 } { #2 }
 }

\tl_new:N \l__simone_des_first_tl
\tl_new:N \l__simone_des_second_tl

\cs_new_protected:Nn \simone_des:nn
 {
  \regex_match:nnTF { \cD_ } { #1 }
   {
    \tl_set:Nn \l__simone_des_first_tl { #1 }
    \tl_set:Nn \l__simone_des_second_tl { #2 }
    \regex_replace_once:nnN
     { \cD_(.*)\Z } % whatever after _
     { \cD_\cB\{\1,\u{l__simone_des_second_tl}\cE\} }
     \l__simone_des_first_tl
    \tl_use:N \l__simone_des_first_tl
   }
   {#1\sb{#2}}
 }

\ExplSyntaxOff

\begin{document}

$\des{Q}{1}$

$\des{Q_1}{c}$

\end{document}

enter image description here

egreg
  • 1,121,712