2

Is it possible to check whether a token is a delimiter, i.e (, ), |, \vert, \langle, \rangle, etc without directly checking each of them in a condition?

The structure of delimiter is well described here: https://tex.stackexchange.com/a/296650/213149. It appear to use \delimiter command

So my question is how I can detect such a delimiter in somewhat versatile way using either pure TeX or LaTeX3.

For example, I want to custom macro \isDelimiter{...} to print true or false in the document if it's argument is a delimiter or not respectively.

1 Answer 1

4

I'm not sure this can be useful for your \veca problem. Anyway…

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\isDelimiterTF}{mmm}
 {
  \antshar_isdel:Nnn #1 { #2 } { #3 }
 }

% first check whether #1 is a control sequence
\cs_new:Nn \antshar_isdel:Nnn
 {
  \token_if_cs:NTF #1
   {
    \__antshar_isdel_cs:Nnn #1 { #2 } { #3 }
   }
   {
    \__antshar_isdel_char:Nnn #1 { #2 } { #3 }
   }
 }

% it is a control sequence; first check the two exceptional cases \{ and \}
% which return true; otherwise go on: if the token is not expandable return false
\cs_new:Nn \__antshar_isdel_cs:Nnn
 {
  \str_case:nnF { #1 }
   {
    {\{}{#2}
    {\}}{#2}
   }
   {
    \token_if_expandable:NTF #1
     {
      \__antshar_isdel_csexp:Nnn #1 { #2 } { #3 }
     }
     {
      #3
     }
  }
 }

% the token is expandable, access its expansion
\cs_new:Nn \__antshar_isdel_csexp:Nnn
 {
  \__antshar_isdel_exp:onn { #1 } { #2 } { #3 }
 }

% if the expansion begins with \delimiter return true, otherwise false
\cs_new:Nn \__antshar_isdel_exp:nnn
 {
  \__antshar_isdel_exp_aux:w #1 \q_nil \q_stop { #2 } { #3 }
 }
\cs_generate_variant:Nn \__antshar_isdel_exp:nnn { o }

\cs_new:Npn \__antshar_isdel_exp_aux:w #1 #2 \q_stop #3 #4
 {
  \token_if_eq_meaning:NNTF #1 \delimiter { #3 } { #4 }
 }

% when the token is a character, look at its \delcode;
% if positive return true, otherwise false
\cs_new:Nn \__antshar_isdel_char:Nnn
 {
  \int_compare:nTF { \delcode`#1 > 0 } { #2 } { #3 }
 }

\ExplSyntaxOff

\begin{document}

\verb|a|: \isDelimiterTF{a}{T}{F}

\verb|(|: \isDelimiterTF{(}{T}{F}

\verb|]|: \isDelimiterTF{]}{T}{F}

\verb|\langle|: \isDelimiterTF{\langle}{T}{F}

\verb-\|-: \isDelimiterTF{\|}{T}{F}

\verb|\{|: \isDelimiterTF{\{}{T}{F}

\verb|\lbrace|: \isDelimiterTF{\lbrace}{T}{F}

\verb|\mbox|: \isDelimiterTF{\mbox}{T}{F}

\end{document}

enter image description here

How do we recognize when a control sequence is a delimiter? Its first level expansion should begin with \delimiter or, if a character, its \delcode should be positive.

The check for a character is therefore obvious. For a control sequence we need first to see whether it is expandable or not. But also we need to take care of \{ and \} that are somewhat special, so these cases are settled by themselves.

If the control sequence we're examining is not expandable, it is not a delimiter (maybe other exceptions like \{ and \} must be added with some font packages). If it is expandable, we look at its first level expansion by calling

\__antshar_isdel_exp:onn { #1 } { #2 } { #3 }

so the o argument type will do the required one-level expansion. This will become

\__antshar_isdel_exp_aux:w #1 \q_nil \q_stop { #2 } { #3 }

The definition of \__antshar_isdel_exp_aux:w is

\cs_new:Npn \__antshar_isdel_exp_aux:w #1 #2 \q_stop #3 #4
 {
  \token_if_eq_meaning:NNTF #1 \delimiter { #3 } { #4 }
 }

so the first token in the expansion of the control sequence we're examining becomes #1 and the rest up to \q_nil becomes #2. The rest, that is, #3 and #4 are the true and false text for \isDelimiterTF. The first argument is undelimited, hence it will take the first token in the input stream as its argument; the second argument ends when TeX finds \q_stop.

The strange \q_nil is there because if you try \isDelimiter{\empty}{T}{F} there would be nothing in the expansion; in this case \q_nil is taken as #1 and #2 is empty. But, since \q_nil is not \delimiter, all goes through.

8
  • Thank you so much! I appreciate that.
    – antshar
    May 9, 2022 at 8:56
  • Can you explain how \cs_new:Npn \__antshar_isdel_exp_aux:w #1 #2 \q_stop #3 #4 {...} works? What does \q_stop do?
    – antshar
    May 9, 2022 at 10:34
  • @antshar The expansion of the token is placed in the input stream and the first token in its expansion becomes #1, all the rest is #2. If the given token expands to nothing you'd have a problem, though. If you fear this, add a different quark before \q_stop.
    – egreg
    May 9, 2022 at 10:35
  • Does it mean that #1 #2 becomes first argument of \__antshar_isdel_exp_aux:w and #3 #4 is the second one?
    – antshar
    May 9, 2022 at 10:38
  • @antshar Not at all. I'll add some explanations.
    – egreg
    May 9, 2022 at 10:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .