6

I want to make a command that detects if the next token written in the document is a closing brace.

My best approach is to use the \@ifnextchar command. In fact, the following code:

\makeatletter
{
\@ifnextchar{\egroup}{yes}{no}
}
\makeatother

Does print yes. But when i try to define a command \demo in a .sty file as:

\newcommand{\demo}
{
\@ifnextchar{\egroup}{yes}{no}
}

and make the call:

{\demo}

It prints no. I suppose that this happens because LaTeX detects a "end of command" token before returning to the document. Anyway, I would like to know the actual reason of why this happens, and how should I define the \demo command for printing yes in the last example.

edit:

In a blank document it actually prints yes. This is my minimal working example where it prints no:

\documentclass[a5paper]{book}

\usepackage{xparse}

\NewDocumentCommand{\wrapper}{ >{\SplitList{.}} m }
{
\begin{itemize}
\ProcessList{#1}{\entry}
\end{itemize}
}

\newcommand{\entry}[1]
{
\item \begin{math} #1 \end{math}
}
\makeatletter
\newcommand{\demo}{\@ifnextchar{\egroup}{yes}{no}}
\makeatother

\begin{document}

\wrapper{a.b.{\demo}.d} prints no
but {\demo} prints yes


\end{document}

edit 2:

I just noticed that in my project, detecting that \demo is the last one within a \wrapper could be enough. So:

\wrapper{\demo.\demo}

should print no first and then yes. Now that I look at it this way, I'm sure it has to be another way to get this information easier.

11
  • 1
    I get yes. Can you show a minimal example?
    – egreg
    Apr 26, 2014 at 15:59
  • (a) Your real world macro \demo should not contain any code between \@ifnextchar with its three arguments and the end of the macro. Otherwise \@ifnextchar would just see the first token of the code. (b) \@ifnextchar gobbles following spaces (for example, the space in the definition by the line end). If spaces matter, then \ltx@ifnextchar@nospace of package ltxmcds can be used. Apr 26, 2014 at 16:06
  • The braces around \demo are stripped off by effect of \SplitList.
    – egreg
    Apr 26, 2014 at 16:29
  • A much slower routine needs to be used if you don't want the braces are stripped off. Can you tell why you want to do this?
    – egreg
    Apr 26, 2014 at 16:36
  • 1
    @A.Ellett That's a general TeX feature: when arguments are grabbed (delimited or undelimited) a pair of braces is stripped off unless, in the delimited case, they would leave unbalanced braces.
    – egreg
    Apr 26, 2014 at 17:22

2 Answers 2

5

If all you want is that \demo prints yes if it's the last item in the list, then this should work:

\documentclass[a5paper]{book}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\wrapper}{ m }
 {
  \begin{itemize}
  \azpillaga_wrapper:n { #1 }
  \end{itemize}
 }

\NewDocumentCommand{\demo}{ }
 {
  \azpillaga_demo:
 }

\seq_new:N \l__azpillaga_input_seq
\tl_new:N \l__azpillaga_last_tl
\bool_new:N \l__azpillaga_last_item_bool
\cs_new_protected:Npn \azpillaga_wrapper:n #1
 {
  \bool_set_false:N \l__azpillaga_last_item_bool
  \seq_set_split:Nnn \l__azpillaga_input_seq { . } { #1 }
  \seq_pop_right:NN \l__azpillaga_input_seq \l__azpillaga_last_tl
  \seq_map_inline:Nn \l__azpillaga_input_seq { \entry{##1} }
  \bool_set_true:N \l__azpillaga_last_item_bool
  \entry {\tl_use:N \l__azpillaga_last_tl }
 }
\cs_new:Npn \azpillaga_demo:
 {
  \bool_if:NTF \l__azpillaga_last_item_bool
   {
    yes
   }
   {
    no
   }
 }
\ExplSyntaxOff

\newcommand{\entry}[1]
{
\item \begin{math} #1 \end{math}
}

\begin{document}

Not at the end:
\wrapper{a.b.\demo.d}

At the end:
\wrapper{\demo.\demo}

\end{document}

enter image description here

5
  • This is definitively a working answer. It's important to keep my document free of expl3 syntax. Can someone build an alternative? Apr 26, 2014 at 17:33
  • @MartinAzpillaga If you use xparse you have expl3 anyway.
    – egreg
    Apr 26, 2014 at 17:35
  • At this moment, I know nothing about expl3. As I mentioned above, this code is part of a more complicated structure which I would be unable to switch to expl3 right now. If I can't get a non-expl3 answer, I'll probably post a new question with the whole structure so a full restructuring can be made. Apr 26, 2014 at 17:52
  • Sorry, you can't do this with xparse only.
    – egreg
    Apr 26, 2014 at 17:58
  • Then I think this is the best answer. Good job :) Apr 27, 2014 at 12:16
1

Though this has already been answered by @egreg , here's a solution that superficially avoids expl3: as already mentioned by egreg, since xparse is built on expl3 there really is no avoiding it.

If all you want to do is to be able to detect whether \demo has been passed as the last item in a list, this should work:

\documentclass[a5paper]{book}
\usepackage{xparse}

\makeatletter

\def\mylastitem{\relax}

\NewDocumentCommand\wrapper{ m }
  {\ae@wrapper{#1\mylastitem}}

\NewDocumentCommand{\ae@wrapper}{ >{\SplitList{.}} m }
{\begin{itemize}
 \ProcessList{#1}{\entry}
 \end{itemize}}

\newcommand{\entry}[1]{\item \begin{math} #1 \end{math}}

\newcommand\demo{\@ifnextchar\mylastitem{\textit{yes}}{\textit{no}}}

\makeatother

\begin{document}

\wrapper{acd.b.{\demo}.d} prints \textit{no}

\wrapper{acd.b.c.\demo} prints \textit{yes}

\end{document}

However, I should point out that the community here will most likely frown on this sort of approach since I'm mixing the older style @ notation with an implicit expl3 style package. Nevertheless, if you still feel the need to know how to get this to work without having to actually write expl3 code yourself, the above should do the trick for you.

You must log in to answer this question.

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