如何解析 TeX 宏中的多个参数

如何解析 TeX 宏中的多个参数

我已经格式化了日期{yyyy-mm-dd}。我想以以下形式显示日期之间的时间间隔:Y 年,M 月。鉴于日期的格式,使用算术似乎比将它们作为日期进行操作更容易。

我正在尝试使用两个日期参数调用宏,并解析每个参数。这是失败的部分,我认为这是由于两个日期参数及其分隔符之间的相互作用。有没有办法在宏定义中做到这一点,还是需要定义另一个宏来分别对每个日期参数起作用?

\documentclass{article}

\newcount\elapsedyears
\newcount\elapsedmonths

\def\elapsedyearsmonths[#1-#2-#3]#4-#5-#6\relax{%
  \ifnum#2>#5
    \elapsedyears=\numexpr#1-#4
    \elapsedmonths=\numexpr#2-#5+1
  \else
    \elapsedyears=\numexpr#1-#4-1
    \elapsedmonths=\numexpr#2-#5+12
  \fi
  \the\elapsedyears{}years, \the\elapsedmonths{} months
}

\begin{document}

\def\myenddate{2013-10-22}
\def\mystartdate{2010-09-15}

\elapsedmonthsyears{2014-11-06}{2012-02-03}

\elapsedmonthsyears\myenddate\mystartdate

\end{document}

我现在明白我必须创建更多的条件语句来将“年”和“月”也复数化或不复数化。

干杯

答案1

如上所述,发布的代码产生

! Undefined control sequence.
l.22 \elapsedmonthsyears

因此将最后两个调用改为使用\elapsedyearsmonths

生产

! Use of \elapsedyearsmonths doesn't match its definition.
l.22 \elapsedyearsmonths{

因为第 22 行的调用后面跟着一个{

(错误消息中的行尾显示 TeX 在该点停止)

正如所写,宏[之前有一个分隔符#1,因此后面必须跟[

将调用改为

\elapsedyearsmonths[2014-11-06]2012-02-03\relax

\elapsedyearsmonths[\myenddate]\mystartdate\relax

生产

! Paragraph ended before \elapsedyearsmonths was complete.
<to be read again> 
                   \par 
l.25 

这很好,这意味着第一次调用做了一些事情,因为错误是第 25 行。

-第二次调用失败,因为 TeX 在寻找不存在的时越过了空白行。

添加宏来扩展参数:

\def\xelapsedyearsmonths#1#2{%
    \edef\tmp{\noexpand\elapsedyearsmonths[#1]#2\relax}%
    \tmp}

并将调用改为

\xelapsedyearsmonths{2014-11-06}{2012-02-03}

\xelapsedyearsmonths\myenddate\mystartdate

运行无错误

在此处输入图片描述

\documentclass{article}

\newcount\elapsedyears
\newcount\elapsedmonths

\def\elapsedyearsmonths[#1-#2-#3]#4-#5-#6\relax{%
  \ifnum#2>#5
    \elapsedyears=\numexpr#1-#4
    \elapsedmonths=\numexpr#2-#5+1
  \else
    \elapsedyears=\numexpr#1-#4-1
    \elapsedmonths=\numexpr#2-#5+12
  \fi
  \the\elapsedyears{}years, \the\elapsedmonths{} months
}

\def\xelapsedyearsmonths#1#2{%
  \edef\tmp{\noexpand\elapsedyearsmonths[#1]#2\relax}%
  \tmp}

\begin{document}

\def\myenddate{2013-10-22}
\def\mystartdate{2010-09-15}

\xelapsedyearsmonths{2014-11-06}{2012-02-03}

\xelapsedyearsmonths\myenddate\mystartdate

\end{document}

答案2

以下是一个实现expl3

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

% the user level command; with :oo both arguments are expanded once
% before being processed
\NewDocumentCommand{\elapsedmonthsyears}{mm}
 {
  \jonathan_elapsed_months:oo{#1}{#2}
 }

% some variables for later usage
\seq_new:N \l_jonathan_end_date_seq
\seq_new:N \l_jonathan_start_date_seq
\int_new:N \l_jonathan_months_int

\cs_new_protected:Npn \jonathan_elapsed_months:nn #1 #2
 {
  % split the first argument into components {yearend}{monthend}[dayend}
  \seq_set_split:Nnn \l_jonathan_end_date_seq { - } { #1 }  
  % split the second argument into components {yearstart}{monthstart}[daystart}
  \seq_set_split:Nnn \l_jonathan_start_date_seq { - } { #2 }
  % compute d=(yearend*12+monthend)-(yearstart*12+monthstart)
  % which gives the difference in months
  \int_set:Nn \l_jonathan_months_int
   {
    (
     \seq_item:Nn \l_jonathan_end_date_seq { 1 } * 12 +
     \seq_item:Nn \l_jonathan_end_date_seq { 2 } 
    )
    -
    (
     \seq_item:Nn \l_jonathan_start_date_seq { 1 } * 12 +
     \seq_item:Nn \l_jonathan_start_date_seq { 2 } 
    )
   }
  % print the number of years, d/12 (truncated)
  \int_to_arabic:n { \int_div_truncate:nn { \l_jonathan_months_int } { 12 } }
  \nobreakspace
  year
  % if the number of years is =1 don't add an "s"
  \int_compare:nF { \int_div_truncate:nn { \l_jonathan_months_int } { 12 } = 1}{s}
  % print a comma with a space
  ,~
  % print the number of months, d mod 12
  \int_to_arabic:n { \int_mod:nn { \l_jonathan_months_int } { 12 } }
  \nobreakspace
  month
  % if the number of months is =1 don't add an "s"
  \int_compare:nF { \int_mod:nn { \l_jonathan_months_int } { 12 } = 1 }{s}
 }

% generate the :oo variant
\cs_generate_variant:Nn \jonathan_elapsed_months:nn { oo }
\ExplSyntaxOff

\begin{document}

\def\myenddate{2013-10-22}
\def\mystartdate{2010-09-15}

\elapsedmonthsyears{2014-11-06}{2012-02-03}

\elapsedmonthsyears\myenddate\mystartdate

\end{document}

在此处输入图片描述

答案3

不算好,但也不算太坏:

%begin time definitions
\newcount\eyear
\newcount\emonth
\newcount\eday
\newcount\ehour
\newcount\eminutes
% \time
\newcount\hour
\newcount\hours
\newcount\minutes
\hour=\time \divide\hour by 60 
\minutes=\time
\hours=\hour \multiply\hours by 60 
\advance \minutes by -\hours
\def\fromdate[#1-#2-#3 #4:#5]{%
\eyear=\year%
\emonth=\month%
\eday=\day%
\ehour=\hour%
\eminutes=\minutes%
\def\elapsed{%
\vskip1\baselineskip From Date #1-#2-#3 #4:#5\vskip1\baselineskip%
\advance\eyear by -#1 \multiply\eyear by-1%
\advance\emonth by-#2 \multiply\emonth by-1%
\advance\eday by -#3 \multiply\eday by-1%
\advance\ehour by -#4 \multiply\ehour by-1%
\advance\eminutes by -#5 \multiply\eminutes by-1%
 Difference (Years:\the\eyear)-(Months:\the\emonth)-(Days:\the\eday)%
(Hours:\the\ehour):(Minutes:\the\eminutes)
}%
Current Date \the\year-\the\month-\the\day\ \ifnum\hour<10%
0\fi\the\hour:\ifnum\minutes<10 0\fi\the\minutes%
\elapsed%
\vskip2\baselineskip
}%
\fromdate[2013-10-3 1:10]
\fromdate[2012-1-30 23:10]
\fromdate[2010-12-10 3:10]
%end  \time defintions
\bye

输出

相关内容