![使用数字和可选字母解析参数](https://linux22.com/image/307025/%E4%BD%BF%E7%94%A8%E6%95%B0%E5%AD%97%E5%92%8C%E5%8F%AF%E9%80%89%E5%AD%97%E6%AF%8D%E8%A7%A3%E6%9E%90%E5%8F%82%E6%95%B0.png)
如何定义一个宏,它接受由数字和选修的字母,然后根据字母进行分支?
由于这是现有包的扩展,最好不要使用任何包或 LaTeX3;此外,由于语法尚未定义,您可以使用字母在数字后面或前面来实现答案,使用任何您想要的分隔符(没有更好)。
\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}
答案1
\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}
答案2
您可以在语法上自由发挥,允许键出现在年份之前或之后(实际上,键可以在任何地方出现多次;出现的最后一个字母将设置行为)。
\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:
}
\cs_new_protected:Npn \astrinus_add_token:n #1
{
\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}
输入是逐个标记扫描的;数字在 中累积\l_astrinus_myparse_year_tl
,而字母设置为\l_astrinus_myparse_key_tl
。最后我们匹配\l_astrinus_myparse_key_tl
可能的情况并执行适当的操作。
答案3
一种使用 e-TeX 提供可扩展解决方案的方法。其思想是循环输入,测试每个标记是否是数字。如果是,则保留它,如果不是,则假设我们已经到达数字的末尾并触发开始/中间/结束阶段。
\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}
从这个意义上来说,解决方案类似于大卫·卡莱尔除了数字检测是在宏中完成的而不是使用 TeX 原始分配之外。