8

So here is a way to get the first, second, and remaining elements (characters) of a given string:

\makeatletter
\newcommand{\firstof}[1]{\@car#1\@nil}
\newcommand{\secondof}[1]{\expandafter\@car\@cdr#1\@nil\@nil}
\newcommand{\restof}[1]{\expandafter\@cdr\@cdr#1\@nil\@nil}
\makeatother

But try as I may, I could not find a way to get the third element -- the MWE below shows the obvious first attempt... Now, I understand that this is related to the complicated way in which TeX expands its macros, but I would appreciate any help, since I am stuck! (I tried a couple more of things after that first attempt (some inspired by this), but nothing worked.) Thank you in advance!

\documentclass[a4paper,12pt,dvipsnames*]{article}

\makeatletter
\newcommand{\firstof}[1]{\@car#1\@nil}
\newcommand{\secondof}[1]{\expandafter\@car\@cdr#1\@nil\@nil}
\newcommand{\restof}[1]{\expandafter\@cdr\@cdr#1\@nil\@nil}

% Does not work!
\newcommand{\thirdof}[1]{\expandafter\@cdr\@cdr\@cdr#1\@nil\@nil\@nil}
\makeatother

\begin{document}

\section*{Some topic}
  \begin{itemize}
    \item \verb+\firstof{ABCD}+: $\firstof{ABCD}$
    \item \verb+\secondof{ABCD}+: $\secondof{ABCD}$
    \item \verb+\restof{ABCD}+: $\restof{ABCD}$
    % \item \verb+\thirdof{ABCD}+: $\thirdof{ABCD}$ % DOES NOT WORK
  \end{itemize}

\end{document}

enter image description here

2

3 Answers 3

6

Using a bunch of \expandafter tokens might be fun, but there are much better ways now than \@car and \@cdr.

\documentclass{article}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\firstof}{m}
 {
  %\tl_item:nn { #1 } { 1 }
  \tl_head:n { #1 }
 }
\NewExpandableDocumentCommand{\secondof}{m}
 {
  \tl_item:nn { #1 } { 2 }
 }
\NewExpandableDocumentCommand{\thirdof}{m}
 {
  \tl_item:nn { #1 } { 3 }
 }
\NewExpandableDocumentCommand{\nthof}{mm}
 {
  \tl_item:nn { #2 } { #1 }
 }

\NewExpandableDocumentCommand{\restof}{O{2}m}
 {
  \tl_range:nnn { #2 } { #1 } { -1 }
 }

\ExplSyntaxOff

\begin{document}

\section*{Some topic}
  \begin{itemize}
    \item \verb+\firstof{ABCD}+: \firstof{ABCD}
    \item \verb+\secondof{ABCD}+: \secondof{ABCD}
    \item \verb+\thirdof{ABCD}+: \thirdof{ABCD}
    \item \verb+\nthof{4}{ABCD}+: \nthof{4}{ABCD}
    \item \verb+\restof{ABCD}+: \restof{ABCD}
    \item \verb+\restof[3]{ABCD}+: \restof[3]{ABCD}
  \end{itemize}

\end{document}

enter image description here

4
  • Mea culpa: I was taken back to the times where I coded in Lisp... Question: where can I find a good tutorial / documentation about these new features? I tried the ovious place, mirrors.up.pt/pub/CTAN/macros/latex/contrib/l3kernel/expl3.pdf, but it does not mention either tl_head or tl_item. Thanks! (And thanks for answer, of course! :-) )
    – wmnorth
    Commented Feb 20 at 10:12
  • 2
    @wmnorth texdoc interface documents all functions expl3 doc is just a high level overview Commented Feb 20 at 10:17
  • @DavidCarlisle Thanks, I will just add that, to get the document I wanted (the one for expl3 stuff) from texdoc.org, I had to search for exactly for 'interface3', otherwise I only got wrong results...
    – wmnorth
    Commented Feb 21 at 17:52
  • @wmnorth sorry, I see I missed a 3 above Commented Feb 21 at 18:30
7

mimic the definition of \@car but taking the third slot (this definition does not check the list is long enough)

enter image description here

\documentclass[a4paper,12pt,dvipsnames*]{article}

\makeatletter
\newcommand{\firstof}[1]{\@car#1\@nil}
\newcommand{\secondof}[1]{\expandafter\@car\@cdr#1\@nil\@nil}
\newcommand{\thirdof}[1]{\@thirdof#1\@nil}
\def\@thirdof#1#2#3#4\@nil{#3}
\newcommand{\restof}[1]{\@restof#1\@nil}
\def\@restof#1#2#3#4\@nil{#4}

% Does not work!

\makeatother

\begin{document}

\section*{Some topic}
  \begin{itemize}
    \item \verb+\firstof{ABCD}+: $\firstof{ABCD}$
    \item \verb+\secondof{ABCD}+: $\secondof{ABCD}$
     \item \verb+\thirdof{ABCD}+: $\thirdof{ABCD}$ % DOES NOT WORK
    \item \verb+\restof{ABCD}+: $\restof{ABCD}$
  \end{itemize}

\end{document}


1
  • Thank your for the answer, although this seems a tad too inflexible for my needs. (Which is my fault, because my question did not specify them.)
    – wmnorth
    Commented Feb 20 at 10:15
2

In case there is a practical use case scenario behind this and not just academical interest:

The concept of "string" is vague in TeX.

What kind of tokens may the string contain?
How do you wish spaces and curly braces to be treated?
What kind of characters may the string contain? Is the .tex-input-file encoded in utf-8 and strings may contain multibyte characters? If so, these need special consideration as with 8-bit TeX-engines multibyte characters may yield as many tokens as bytes are needed for encoding them in the .tex-input-file, which in turn implies that with 8-bit engines such characters cannot be processed as undelimited arguments consisting of a single token not wrapped in curly braces.


For the sake of having fun - how about an \expandafter-orgy?

\documentclass[a4paper,12pt]{article}

\makeatletter
\newcommand{\firstof}[1]{\@car#1\@nil}%
\newcommand{\secondof}[1]{\expandafter\@car\@cdr#1\@nil\@nil}%
\newcommand{\thirdof}[1]{\expandafter\expandafter\expandafter\@car\expandafter\@cdr\@cdr#1\@nil\@nil\@nil}%
% As \@cdr grabs an undelimited argument and a delimited argument, the following, where \@cdr
% is used three times, breaks in case #1 does not contain at least three components that can
% be grabbed as undelimited argument:
\newcommand{\restof}[1]{\expandafter\expandafter\expandafter\@cdr\expandafter\@cdr\@cdr#1\@nil\@nil\@nil}
%----------------------------------------------------------------------------------------------
%
% The following might be of academical interest in case you don't mind 
% - inscrutable behavior in case of the string containing curly braces of category 1/2
% - explicit space tokens being removed and not being counted when detecting/
%   delivering the K-th  element of the string while spaces not being removed
%   from the rest of the string:
%
\@ifdefinable\@stopromannumeral{\chardef\@stopromannumeral=`\^^00}%
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\newcommand\KthOf[3]{%
  % #1 - number K
  % #2 - tokens in case there are no K undelimited arguments.
  % #3 - string
  \romannumeral
  \expandafter\@KthOfCheck\expandafter{\number\numexpr(#1)\relax}{#2}{#3}{\@car}%
}%
\newcommand\RestBehindKthOf[3]{%
  % #1 - number K
  % #2 - tokens in case there are no K undelimited arguments.
  % #3 - string
  \romannumeral
  \expandafter\@KthOfCheck\expandafter{\number\numexpr(#1)\relax}{#2}{#3}{\@cdr}%
}%
\newcommand\@KthOfCheck[4]{%
  % #1 - number K
  % #2 - tokens in case there are no K undelimited arguments.
  % #3 - string
  % #4 = token to prepend when thingies are removed, either \@car or \@cdr
  \ifnum0<#1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {%
    \expandafter\expandafter\expandafter\PassFirstToSecond
    \expandafter\expandafter\expandafter{\expandafter\@cdr
    \romannumeral\numexpr(#1)*(1000)\relax\@nil}{\@KthOfLoop}{#4}%
    {#3}{#2}%
  }{%
    \ifnum0=#1 \expandafter\@firstofone\else\expandafter\@gobble\fi
    {%
      \ifx\@car#4\else\expandafter\@firstoftwo\expandafter\@firstoftwo\fi
    }\@secondoftwo
    {\@stopromannumeral#3}{\@stopromannumeral#2}%
  }%
}%
\newcommand\@KthOfLoop[4]{%
  % #1 = as many m as characters are still to be removed from string #3 before doing #2
  % #2 = token to prepend when thingies are removed, either \@car or \@cdr
  % #3 = remaining String
  % #4 = tokens in case there are no K undelimited arguments.
  \ifcat$\detokenize\expandafter{\@secondoftwo#3{}{}}$%
  \expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
  {%
    \ifx\@nil#1\@nil\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
    {\expandafter\@firstofone\expandafter{\expandafter\@stopromannumeral#2#3\@nil}}%
    {%
      \expandafter\PassFirstToSecond\expandafter{\@cdr#3\@nil}%
      {\expandafter\@KthOfLoop\expandafter{\@cdr#1\@nil}{#2}}{#4}%
    }%
  }%
  {\@stopromannumeral#4}%
}%
%----------------------------------------------------------------------------------------------
\makeatother

\begin{document}

\ttfamily\selectfont\frenchspacing
\noindent
\verb+|\firstof{ABCD}|+: |\firstof{ABCD}|\\
\verb+|\secondof{ABCD}|+: |\secondof{ABCD}|\\
\verb+|\thirdof{ABCD}|+: |\thirdof{ABCD}|\\ % DOES WORK
\verb+|\restof{ABCD}|+: |\restof{ABCD}|\\
\verb+|\KthOf{-1}{There is no minusoneth.}{ABCD}|+: |\KthOf{-1}{There is no minusoneth.}{ABCD}|\\
\verb+|\KthOf{0}{There is no zeroth.}{ABCD}|+: |\KthOf{0}{There is no zeroth.}{ABCD}|\\
\verb+|\KthOf{1}{There is no first.}{ABCD}|+: |\KthOf{1}{There is no first.}{ABCD}|\\
\verb+|\KthOf{2}{There is no second.}{ABCD}|+: |\KthOf{2}{There is no second.}{ABCD}|\\
\verb+|\KthOf{3}{There is no third.}{ABCD}|+: |\KthOf{3}{There is no third.}{ABCD}|\\
\verb*+|\KthOf{3}{There is no third.}{ A B C D }|+: |\KthOf{3}{There is no third.}{ A B C D }|\\
\verb+|\KthOf{4}{There is no fourth.}{ABCD}|+: |\KthOf{4}{There is no fourth.}{ABCD}|\\
\verb+|\KthOf{5}{There is no fifth.}{ABCD}|+: |\KthOf{5}{There is no fifth.}{ABCD}|\\
\verb+|\RestBehindKthOf{-1}{There is no minusoneth.}{ABCD}|+: |\RestBehindKthOf{-1}{There is no minusoneth.}{ABCD}|\\
\verb+|\RestBehindKthOf{0}{There is no zeroth.}{ABCD}|+: |\RestBehindKthOf{0}{There is no zeroth.}{ABCD}|\\
\verb+|\RestBehindKthOf{1}{There is no first.}{ABCD}|+: |\RestBehindKthOf{1}{There is no first.}{ABCD}|\\
\verb+|\RestBehindKthOf{2}{There is no second.}{ABCD}|+: |\RestBehindKthOf{2}{There is no second.}{ABCD}|\\
\verb+|\RestBehindKthOf{3}{There is no third.}{ABCD}|+: |\RestBehindKthOf{3}{There is no third.}{ABCD}|\\
\verb*+|\RestBehindKthOf{3}{There is no third.}{ A B C D }|+: |\RestBehindKthOf{3}{There is no third.}{ A B C D }|\\
\verb+|\RestBehindKthOf{4}{There is no fourth.}{ABCD}|+: |\RestBehindKthOf{4}{There is no fourth.}{ABCD}|\\
\verb+|\RestBehindKthOf{5}{There is no fifth.}{ABCD}|+: |\RestBehindKthOf{5}{There is no fifth.}{ABCD}|

\end{document}

enter image description here

The code above is just in case of academical interest in playing around with macro programming.

In case the .tex-input file is encoded in the multibyte encoding utf-8 and an 8bit-engine is in use, a utf-8-character made up of more than one byte in the .tex-input file may yield more than one token so that you cannot process characters as undelimited arguments that in the .tex-input consist of a single token not enclosed between curly braces.

1
  • Wow this is a very detailed answer! For which I am thankful, although I will have to check it later, with more time :-)
    – wmnorth
    Commented Feb 20 at 10:16

You must log in to answer this question.

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