# Parse argument with a number and an optional letter

How to define a macro which takes a string made by number and an optional letter and then branches on the basis on the letter?
Since this is an extension of an existing package, it is preferable not to use any package or LaTeX3; furthermore, since the syntax is not defined yet, you could implement the answer with the letter following or preceding the number, with any separator you want (none is better).

\documentclass{article}

\def\myparse#1{...} % or \newcommand{\myparse}[1]{...}

% Suppose the letter has to be after the number with no separator,
% and the command branches on letters "b", "m", "e" to represent
% the beginning, middle or end of a year.

\begin{document}
\myparse{2004b} % Should print "Beginning of 2004"
\myparse{2005}  % Should print "2005"
\myparse{2005m} % Should print "2005" too
\myparse{2006e} % Should print "End of 2006"
\end{document}

• Why complicating it too much? xparse and or xstring are quite stable packages which can be used basically everywhere?
– user31729
Mar 9, 2015 at 10:36
• We might need some more context: for example, how are you defining a 'number' here, do you need an expandable solution, etc. Mar 9, 2015 at 10:50
• @JosephWright "Number": sequence of digits (we only deal with positive integers). The number needs to be handled by pgf, but there is no imaginable need to use macros as arguments. Mar 9, 2015 at 10:53

\documentclass{article}

\makeatletter
\def\myparse#1{\afterassignment\xmyparse\@tempcnta#1\relax}
\def\xmyparse#1\relax{\csname myparsexx#1\endcsname}
\def\myparsexxb{Beginning of \the\@tempcnta}
\def\myparsexx{\the\@tempcnta}
\def\myparsexxm{\the\@tempcnta}
\def\myparsexxe{End of \the\@tempcnta}
\makeatother

% Suppose the letter has to be after the number with no separator,
% and the command branches on letters "b", "m", "e" to represent
% the beginning, middle or end of a year.

\begin{document}
\myparse{2004b} % Should print "Beginning of 2004"

\myparse{2005}  % Should print "2005"

\myparse{2005m} % Should print "2005" too

\myparse{2006e} % Should print "End of 2006"
\end{document}

• Superb! I really need to read the TeXbook... The definition of \myparse assigns the number to \@tempcnta and gobbles it, then the non-number part of #1 is passed to \xmyparse, right? Mar 9, 2015 at 11:04
• @Astrinus: Right. The really cute idiom, IMHO, is the b, e, m dispatch via the macro identifiers. Mar 9, 2015 at 11:17
• @Astrinus yes, the \relax is added as a terminator so after the number assignment xmyparse skoops up everything up to \relax which is nothing or a letter (hopefully:-) Mar 9, 2015 at 11:22

You can be liberal in your syntax, allowing the key before or after the year (actually, the key can appear anywhere and multiple times; the last letter appearing will set the behavior).

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\myparse}{m}
{
\astrinus_myparse:n { #1 }
}

\tl_new:N \l_astrinus_myparse_year_tl
\tl_new:N \l_astrinus_myparse_key_tl

\cs_new_protected:Npn \astrinus_myparse:n #1
{
\tl_clear:N \l_astrinus_myparse_year_tl
\tl_clear:N \l_astrinus_myparse_key_tl
\tl_map_inline:nn { #1 } { \astrinus_add_token:n { ##1 } }
\astrinus_print:
}

{
\tl_if_in:nnTF { 0123456789 } { #1 }
{
\tl_put_right:Nn \l_astrinus_myparse_year_tl { #1 }
}
{
\tl_set:Nn \l_astrinus_myparse_key_tl { #1 }
}
}

\cs_new_protected:Npn \astrinus_print:
{
\str_case:Vn \l_astrinus_myparse_key_tl
{
{b}{Beginning~of~}
{e}{End~of~}
}
\tl_use:N \l_astrinus_myparse_year_tl
}

\cs_generate_variant:Nn \str_case:nn { V }
\ExplSyntaxOff

\begin{document}

\myparse{2004b} % Should print "Beginning of 2004"

\myparse{b2004} % Should print "Beginning of 2004"

\myparse{2005}  % Should print "2005"

\myparse{2005m} % Should print "2005" too

\myparse{m2005} % Should print "2005" too

\myparse{2006e} % Should print "End of 2006"

\myparse{e2006} % Should print "End of 2006"

\end{document}


The input is scanned token by token; digits are accumulated in \l_astrinus_myparse_year_tl, while a letter sets \l_astrinus_myparse_key_tl. Finally we match \l_astrinus_myparse_key_tl with the possible cases and do the appropriate action.

• This is also superb, but it loads xparse... and I'm not the package maintainer, who absolutely doesn't want to make it depends on any further package. Mar 9, 2015 at 11:06
• @Astrinus, tell him that if xparse is used, his package will be future-proof. Mar 9, 2015 at 11:14

An approach using e-TeX to give an expandable solution. The idea is to loop over the input, testing if each token is a digit or not. If it is, simply keep it, while if it's not then assume we've reached the end of the number and trigger a begin/middle/end phase.

\documentclass{article}
\usepackage[T1]{fontenc} % Just so \meaning looks right when printed

\makeatletter
\newcommand*\myparse[1]{%
\myparse@auxi#1\q@tail\q@stop{}%
}
\newcommand*\myparse@auxi[1]{%
\ifx\q@tail#1%
\expandafter\myparse@end
\fi
\if\number\numexpr0#1-0#1\relax0%
\expandafter\myparse@auxii
\else
\expandafter\myparse@auxiii
\fi
#1%
}
\newcommand*\myparse@auxii{}
\def\myparse@auxii#1#2\q@stop#3{%
\myparse@auxi#2\q@stop{#3#1}%
}
\newcommand*\myparse@auxiii{}
\def\myparse@auxiii#1#2\q@stop{%
\csname myparse@aux@#1\endcsname
}
\newcommand*\myparse@aux@b[1]{Beginning of #1}
\newcommand*\myparse@aux@m[1]{#1}
\newcommand*\myparse@aux@e[1]{End of #1}

\newcommand*\myparse@end{}
\def\myparse@end#1\q@stop#2{#2}

\def\q@tail{\q@tail}
\makeatother
\begin{document}
\myparse{2004b} % Should print "Beginning of 2004"

\myparse{2005}  % Should print "2005"

\myparse{2005m} % Should print "2005" too

\myparse{2006e} % Should print "End of 2006"

\edef\test{\myparse{2006e}}\meaning\test
\end{document}


The solution is in this sense similar to that by David Carlisle except that the digit detection is done in macros rather than using a TeX primitive assignment.

• I'm assuming 'well-behaved' input, no spaces, no macros, etc. but the question seems to suggest this is OK. Mar 9, 2015 at 11:28
• I've accepted David Carlisle answer, because is shorter and simpler and, for the time being, it is enough. But this is beautiful (e)TeX too! Should the need arise, I'll remember of this answer (upvoted). Mar 9, 2015 at 11:58