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?

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 1 '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 1 '18 at 11:47
  • 1
    @StevenB.Segletes Thanks! I think that your supplement covers all my cases – Simone Gaiarin Aug 3 '18 at 6:40
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}
4

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

  • 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

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.