TransWikia.com

How to check if the argument of a macro has an underscore?

TeX - LaTeX Asked by Ruco on November 29, 2020

I’m using the glossary definition from What is the best way for a list of nomenclature?. I need a macro that checks if the argument contains underscore symbol ("_"). I defined myfun but the argument inside the macro is acrshort(symbI) instead of F_a. How can I solve this issue? Thank you for advance!!

documentclass{article}

usepackage{xspace}
usepackage[acronym,nonumberlist]{glossaries}

renewcommand{acronymname}{List of Notations}

newglossarystyle{mystyle}{%
  setglossarystyle{long}%
  renewenvironment{theglossary}%
     {begin{longtable}[l]{@{}p{0.1hsize}p{0.8hsize}}}%
     {end{longtable}}%
  renewcommand*{glsgroupheading}[1]{%
     multicolumn{2}{@{}l}{bfseriesglsgetgrouptitle{##1}}[5pt]}%
}

newcommand*{Rgroupname}{Roman Symbols}
newcommand*{Ggroupname}{Greek Symbols}

newcommand*{myacro}[4][sort=s]{%
  newacronym[#1]{#2}{#3}{#4}%
  globalexpandafterdefcsname #2endcsname{acrshort{#2}}%
}

myacro[sort=ra]{symbI}{ensuremath{F_a}xspace}{some explanation for $F$}
myacro[sort=rb]{symbII}{ensuremath{M}xspace}{some explanation for $M$}
myacro[sort=ga]{symbIII}{ensuremath{alpha}xspace}{some explanation for $alpha$}
myacro[sort=rc]{symbIV}{ensuremath{U}xspace}{some explanation for $u$}

makeglossaries


usepackage{listofitems}

newcommand{myfun}[1]{
    setsepchar{_}
    readlistmymat{#1}
    ifnummymatlen>1
    textbf{Do something when the argument has _}
    else
    textbf{Do something when the argument does not have _}
    fi
    textbf{the argument is: } showitems*mymat
}

begin{document}

printglossary[style=mystyle,type=acronymtype]

section*{Math section}

begin{equation}
   symbI = symbII symbIII
end{equation}


$ myfun{symbI} $

end{document}  

The code returns:

enter image description here

and I expected to obtain:

enter image description here

(edit) Second code from Steven B. Segletes’ code

If I use a macro to define a new acronym the code doesn’t works. Now, I’m using mysubscripta in simbV to add _a in the definition of the acronym.

documentclass{article}
usepackage{xspace}
usepackage[acronym,nonumberlist]{glossaries}

renewcommand{acronymname}{List of Notations}

newglossarystyle{mystyle}{%
  setglossarystyle{long}%
  renewenvironment{theglossary}%
     {begin{longtable}[l]{@{}p{0.1hsize}p{0.8hsize}}}%
     {end{longtable}}%
  renewcommand*{glsgroupheading}[1]{%
     multicolumn{2}{@{}l}{bfseriesglsgetgrouptitle{##1}}[5pt]}%
}

newcommand*{Rgroupname}{Roman Symbols}
newcommand*{Ggroupname}{Greek Symbols}

newcommand*{myacro}[4][sort=s]{%
  newacronym[#1]{#2}{#3}{#4}%
  globalexpandafterdefcsname #2endcsname{acrshort{#2}}%
  globalexpandafterdefcsname #2defendcsname{#3}%
}

newcommand{mysubscripta}[1]{#1_a}

myacro[sort=ra]{symbI}{ensuremath{mathrm{F_a}}xspace}{some explanation for $F$}
myacro[sort=rb]{symbII}{ensuremath{M_d^e}xspace}{some explanation for $M$}
myacro[sort=ga]{symbIII}{ensuremath{alpha}xspace}{some explanation for $alpha$}
myacro[sort=rc]{symbIV}{ensuremath{U}xspace}{some explanation for $u$}
myacro[sort=rc]{symbV}{ensuremath{mathrm{mysubscripta{F}}}xspace}{some explanation for $F$}

makeglossaries


newcommand{myfun}[1]{
    expandafterexpandafterexpandafterfindus
    expandafterexpandafterexpandafter{csname#1defendcsname}%
    {has _}{does not have _}
}
usepackage{tokcycle}
newcommandfindus[3]{%
  gdefusfound{F}%
  tokcycle{ifx_##1gdefusfound{T}fi}{processtoks{##1}}{}{}{#1}%
  tctestifcon{if Tusfound}{#2}{#3}}
begin{document}

printglossary[style=mystyle,type=acronymtype]

section*{Math section}

begin{equation}
   symbI = symbII symbIII
end{equation}

symbI $ myfun{symbI} $

symbII $ myfun{symbII} $

symbV $ myfun{symbV} $

end{document}

The main objective of solving this issue is to define a macro to add a subscript and superscript to an acronym and to avoid the double subscript/superscript error. For example, I want to do myfun{symbI} and it will retunrs F_{ab}^{c} where symbI is F_a or myfun{symbII} and it will returns M_{db}^{ec} where simbII is M_d^e.

2 Answers

The macro findus searches the unexpanded argument for a _ and forks to #2 or #3 accordingly. I have incorporated it into the OP's myfun.

It works even if the _ is embedded down in a group, as in the case for mathrm{F_a}.

REEDITED to handle OP's additional case, in which the _ was not explicit, but contained in a macro definition. I this case, I adjusted the macro findus to apply a protected@edef to its argument, to expand as much as possible. In this way it can find content that expands to _, in this case, mysubscripta.

documentclass{article}

usepackage{xspace}
usepackage[acronym,nonumberlist]{glossaries}

renewcommand{acronymname}{List of Notations}

newglossarystyle{mystyle}{%
  setglossarystyle{long}%
  renewenvironment{theglossary}%
     {begin{longtable}[l]{@{}p{0.1hsize}p{0.8hsize}}}%
     {end{longtable}}%
  renewcommand*{glsgroupheading}[1]{%
     multicolumn{2}{@{}l}{bfseriesglsgetgrouptitle{##1}}[5pt]}%
}

newcommand*{Rgroupname}{Roman Symbols}
newcommand*{Ggroupname}{Greek Symbols}

newcommand*{myacro}[4][sort=s]{%
  newacronym[#1]{#2}{#3}{#4}%
  globalexpandafterdefcsname #2endcsname{acrshort{#2}}%
  globalexpandafterdefcsname #2defendcsname{#3}%
}

newcommand{mysubscripta}[1]{#1_a}

myacro[sort=ra]{symbI}{ensuremath{mathrm{F_a}}xspace}{some explanation for $F$}
myacro[sort=rb]{symbII}{ensuremath{M}xspace}{some explanation for $M$}
myacro[sort=ga]{symbIII}{ensuremath{alpha}xspace}{some explanation for $alpha$}
myacro[sort=rc]{symbIV}{ensuremath{U}xspace}{some explanation for $u$}
myacro[sort=rc]{symbV}{ensuremath{mathrm{mysubscripta{F}}}xspace}{some explanation for $F$}

makeglossaries


usepackage{listofitems}

newcommand{myfun}[1]{
    expandafterexpandafterexpandafterfindus
    expandafterexpandafterexpandafter{csname#1defendcsname}%
    {has _}{does not have _}
}
usepackage{tokcycle}
makeatletter
newcommandfindus[3]{%
  protected@edeftmp{#1}%
  gdefusfound{F}%
  deftmpA{tokcycle{tctestifx{_####1}{gdefusfound{T}}{}}
  {processtoks{####1}}{}{}}%
  expandaftertmpAexpandafter{tmp}%
  tctestifcon{if Tusfound}{#2}{#3}}
makeatother
begin{document}

printglossary[style=mystyle,type=acronymtype]

section*{Math section}

begin{equation}
   symbI = symbII symbIII = symbV
end{equation}

symbI $ myfun{symbI} $

symbII $ myfun{symbII} $

symbV $ myfun{symbV} $
end{document}  

enter image description here

Answered by Steven B. Segletes on November 29, 2020

If you do

myacro[sort=ra]{symbI}{ensuremath{F_a}xspace}{some explanation for $F$}

, then the ⟨control sequence⟩ symbI will not deliver the tokens ensuremath{F_a}xspace but will deliver a call to acrshort while acrshort is not fully expandable. What does this mean? Expansion takes place in TeX's gullet. (Temporary) Assignments etc take place in TeX's stomach. Some tokens coming from expanding acroshort... are intended to trigger (temporary) assignments or changes of fonts etc and therefore need to be processed by the stomach for subsequent tokens also coming from expanding acroshort... being processed/further expanded correctly.
So you need a check which takes place in TeX's stomach while all checking and forking by means of expandable if.. ...else ... fi-tokens and whatsoever intriguing macro-trickery can take place only at a prior stage, in TeX's gullet. Thus your request is sort of contradictory to the ways in which TeX works.

But the acronym-package internally defines a control sequence glo@symbI@short which delivers the result of applying protected@edef to the tokens ensuremath{F_a}xspace.

Thus you can get hold of the tokens passed to myacro via

csname glo@expandafterexpandafterexpandafterglsdetoklabel
            expandafterexpandafterexpandafter{expandafter@gobblestring⟨control sequence⟩}@shortendcsname

The underscore is nested in curly argument-braces of ensuremath.

So you need a routine for detecting underscores that might be nested in curly braces. In the example below I wrote my own routine CheckWhetherUnderscore for detecting whether a sequence of tokens contains an underscore of category code 8(subscript).

In order to find out if the expansion of the acronym underlying SymbI delivers an underscore you can apply CheckWhetherUnderscore to the result of expanding glo@symbI@short.

But this does not deliver information whether the expansion of the acronym underlying SymbI delivers control sequences which themselves expand to stuff with underscores.

Summa summarum:

You wish a check whereby myfun's argument contains SymbI and/or whatsoever other stuff (which probably isn't fully expandable either) while SymbI cannot be used as it is not fully expandable.

All I can do for you is provide a routine CheckWhetherUnderscore for detecting whether a sequence of tokens contains an underscore of category code 8(subscript) and show how to apply it to the top-level-expansion of glo@symbI@short.

Be aware: In case the top-level-expansion of glo@symbI@short contains an underscore, the routine CheckWhetherUnderscore detects the presence of that underscore no matter if that underscore would get gobbled/removed when further processing the tokens coming from expanding glo@symbI@short.

documentclass{article}

makeatletter
%%///////////////// Code of my own routine for defining checks ////////////////
%%////////////////////// for presence of token sequences //////////////////////
%%=============================================================================
%% Paraphernalia:
%%    UD@firstoftwo, UD@secondoftwo,
%%    UD@PassFirstToSecond, UD@Exchange, UD@removespace
%%    UD@CheckWhetherNull, UD@CheckWhetherBrace,
%%    UD@CheckWhetherLeadingTokens, UD@ExtractFirstArg
%%=============================================================================
newcommandUD@firstoftwo[2]{#1}%
newcommandUD@secondoftwo[2]{#2}%
newcommandUD@PassFirstToSecond[2]{#2{#1}}%
newcommandUD@Exchange[2]{#2#1}%
newcommandUD@removespace{}UD@firstoftwo{defUD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
newcommandUD@CheckWhetherNull[1]{%
  romannumeralexpandafterUD@secondoftwostring{expandafter
  UD@secondoftwoexpandafter{expandafter{string#1}expandafter
  UD@secondoftwostring}expandafterUD@firstoftwoexpandafter{expandafter
  UD@secondoftwostring}expandafterz@UD@secondoftwo}%
  {expandafterz@UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
newcommandUD@CheckWhetherBrace[1]{%
  romannumeralexpandafterUD@secondoftwoexpandafter{expandafter{%
  string#1.}expandafterUD@firstoftwoexpandafter{expandafter
  UD@secondoftwostring}expandafterz@UD@firstoftwo}%
  {expandafterz@UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific 
%% token-sequence that does neither contain explicit character tokens of 
%% category code 1 or 2 nor contain tokens of category code 6:
%%.............................................................................
%% UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%%                              {<a <token sequence> without explicit 
%%                                character tokens of category code
%%                                1 or 2 and without tokens of
%%                                category code 6>}%
%%                              {<internal token-check-macro>}%
%%                              {<tokens to be delivered in case
%%                                <argument which is to be checked> has
%%                                <token sequence> as leading tokens>}%
%%                              {<tokens to be delivered in case 
%%                                <argument which is to be checked>
%%                                does not have <token sequence> as
%%                                leading tokens>}%
newcommandUD@CheckWhetherLeadingTokens[3]{%
  romannumeralUD@CheckWhetherNull{#1}{expandafterz@UD@secondoftwo}{%
    expandafterUD@secondoftwostring{expandafter
    UD@@CheckWhetherLeadingTokens#3{relax}#1#2}{}}%
}%
newcommandUD@@CheckWhetherLeadingTokens[1]{%
  expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
  {UD@Exchange{UD@firstoftwo}}{UD@Exchange{UD@secondoftwo}}%
  {expandafterexpandafterexpandafterexpandafter
   expandafterexpandafterexpandafterz@expandafterexpandafter
   expandafter}expandafterUD@secondoftwoexpandafter{string}%
}%
%%-----------------------------------------------------------------------------
%% UD@internaltokencheckdefiner{<internal token-check-macro>}%
%%                              {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything 
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%-----------------------------------------------------------------------------
newcommandUD@internaltokencheckdefiner[2]{%
  @ifdefinable#1{longdef#1##1#2{{##1}}}%
}%
UD@internaltokencheckdefiner{UD@InternalExplicitSpaceCheckMacro}{ }%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%%   romannumeralUD@ExtractFirstArgLoop{ABCDEUD@SelDOm} yields  {A}
%%
%%   romannumeralUD@ExtractFirstArgLoop{{AB}CDEUD@SelDOm} yields  {AB}
%%.............................................................................
@ifdefinableUD@RemoveTillUD@SelDOm{%
  longdefUD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
}%
newcommandUD@ExtractFirstArgLoop[1]{%
  expandafterUD@CheckWhetherNullexpandafter{UD@firstoftwo{}#1}%
  {z@#1}%
  {expandafterUD@ExtractFirstArgLoopexpandafter{UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% DefineCheckForTokenSequence{<Macro for perfoming the check>}%
%%                             {<internal token-check-macro>}%
%%                             {<token sequence>}%
%%
%% defines <internal token-check-macro> and <Macro for perfoming the check>.
%%
%% Syntax of <Macro for perfoming the check> is:
%%
%% <Macro for perfoming the check>{<tokens to check>}%
%%                                {<token in case <tokens to check> contains
%%                                 <token sequence> at least once>}%
%%                                {<token in case <tokens to check> does not
%%                                 contain <token sequence> >}%
%%
%% !!! <token sequence> must not contain explicit character tokens of catcode 1 or 2 !!!
%% !!! <token sequence> must not contain tokens of catcode 6 !!!
%% !!! <token sequence> must not be empty !!!
%%-----------------------------------------------------------------------------
@ifdefinableDefineCheckForTokenSequence{%
  DeclareRobustCommandDefineCheckForTokenSequence[3]{%
    UD@internaltokencheckdefiner{#2}{#3}%
    newcommand#1[1]{%
      romannumeralUD@CheckForTokenSequenceLoop{##1}{#2}{#3}%
    }%
  }%
}%
newcommandUD@CheckForTokenSequenceLoop[3]{%
  % #1 - <tokens to check>
  % #2 - <internal token-check-macro>
  % #3 - <token sequence>
  % Do:
  %  UD@internaltokencheckdefiner{<internal token-check-macro>}{<token sequence>}%
  %  romannumeralUD@CheckForTokenSequenceLoop{<tokens to check>}%
  %                                            {<internal token-check-macro>}%
  %                                            {<token sequence>}%
  % 
  UD@CheckWhetherNull{#1}{expandafterz@UD@secondoftwo}{%
    UD@CheckWhetherLeadingTokens{#1}{#3}{#2}{%
      expandafterz@UD@firstoftwo
    }{%
      UD@CheckWhetherBrace{#1}{%
        romannumeralexpandafterUD@CheckForTokenSequenceLoop
                     romannumeralUD@ExtractFirstArgLoop{#1UD@SelDOm}{#2}{#3}%
        {UD@firstoftwo}%
        {expandafterUD@secondoftwoUD@secondoftwo}%
      }{%
        UD@CheckWhetherLeadingTokens{#1}{ }{UD@InternalExplicitSpaceCheckMacro}{%
          expandafterUD@firstoftwoUD@secondoftwo
        }{%
          expandafterUD@secondoftwoUD@secondoftwo
        }%
      }%
      {expandafterz@UD@firstoftwo}%
      {%
       {expandafterUD@CheckForTokenSequenceLoopexpandafter{UD@removespace#1}}%
       {expandafterUD@CheckForTokenSequenceLoopexpandafter{UD@firstoftwo{}#1}}%
        {#2}{#3}%
      }%
    }%
  }%
}%
makeatother
%%=============================================================================
%%///////////// End of code of my own routine for defining checks /////////////
%%/////////////////////for presence of token sequences ////////////////////////

% Define a check for presence of `_` :

DefineCheckForTokenSequence{CheckWhetherUnderscore}{InternalUnderscoreCheckMacro}{_}%

usepackage{xspace}
usepackage[acronym,nonumberlist]{glossaries}

renewcommand{acronymname}{List of Notations}

newglossarystyle{mystyle}{%
  setglossarystyle{long}%
  renewenvironment{theglossary}%
     {begin{longtable}[l]{@{}p{0.1hsize}p{0.8hsize}}}%
     {end{longtable}}%
  renewcommand*{glsgroupheading}[1]{%
     multicolumn{2}{@{}l}{bfseriesglsgetgrouptitle{##1}}[5pt]}%
}

newcommand*{Rgroupname}{Roman Symbols}
newcommand*{Ggroupname}{Greek Symbols}

newcommand*{myacro}[4][sort=s]{%
  newacronym[#1]{#2}{#3}{#4}%
  globalexpandafterdefcsname #2endcsname{acrshort{#2}}%
}

myacro[sort=ra]{symbI}{ensuremath{F_a}xspace}{some explanation for $F$}
myacro[sort=rb]{symbII}{ensuremath{M}xspace}{some explanation for $M$}
myacro[sort=ga]{symbIII}{ensuremath{alpha}xspace}{some explanation for $alpha$}
myacro[sort=rc]{symbIV}{ensuremath{U}xspace}{some explanation for $u$}

makeglossaries


usepackage{listofitems}

newcommand{myfun}[1]{%%%
    setsepchar{_}%%%
    readlistmymat{#1}%%%
    ifnummymatlen>1 %%%
    textbf{Do something when the argument has _}
    else
    textbf{Do something when the argument does not have _}
    fi
    textbf{the argument is: } {hbox{csname verbatim@fontendcsnameshowitems*mymat}}%%%
}

begin{document}

printglossary[style=mystyle,type=acronymtype]

section*{Math section}

begin{equation}
   symbI = symbII symbIII
end{equation}


$ myfun{symbI} $

parindent=0pt
vfillhrulevfill

verb|CheckWhetherUnderscore{A BC#1{De{g}F}}{Underscore present}{Underscore not present}|:
CheckWhetherUnderscore{A BC#1{De{g}F}}{Underscore present}{Underscore not present}

vfillhrulevfill

verb|CheckWhetherUnderscore{A BC#1{De{g{_}}F}}{Underscore present}{Underscore not present}|:
CheckWhetherUnderscore{A BC#1{De{g{_}}F}}{Underscore present}{Underscore not present}

vfillhrulevfill

verb|CheckWhetherUnderscore{_}{Underscore present}{Underscore not present}|:
CheckWhetherUnderscore{_}{Underscore present}{Underscore not present}

vfillhrulevfill

verb|CheckWhetherUnderscore{ }{Underscore present}{Underscore not present}|:
CheckWhetherUnderscore{ }{Underscore present}{Underscore not present}

vfillhrulevfill

verb|CheckWhetherUnderscore{}{Underscore present}{Underscore not present}|:
CheckWhetherUnderscore{}{Underscore present}{Underscore not present}

vfillhrulevfill

verb|CheckWhetherUnderscore{A_B}{Underscore present}{Underscore not present}|:
CheckWhetherUnderscore{A_B}{Underscore present}{Underscore not present}

vfillhrulevfill

makeatletter

verb|expandafterexpandafterexpandafterCheckWhetherUnderscore|
verb|expandafterexpandafterexpandafter{%|
verb|  csname glo@expandafterexpandafterexpandafterglsdetoklabel|
verb|              expandafterexpandafterexpandafter{%|
verb|              expandafter@gobblestringsymbI}@shortendcsname|
verb|}{Underscore present}{Underscore not present}|:
expandafterexpandafterexpandafterCheckWhetherUnderscore
expandafterexpandafterexpandafter{%
  csname glo@expandafterexpandafterexpandafterglsdetoklabel
              expandafterexpandafterexpandafter{%
              expandafter@gobblestringsymbI}@shortendcsname
}{Underscore present}{Underscore not present}

makeatother

end{document}

enter image description here

Answered by Ulrich Diez on November 29, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP