宏参数扩展和 edef

宏参数扩展和 edef

我创建了一个宏来识别两种模式之间#1 - #2#1 - #2 - #3并确保表单上的输出# - # - #(对于日期)。

  \def\cal@ymd#1:#2:#3:{#1-#2-#3}
  \def\cal@md#1:#2:#3:{\cal@Year-#1-#2}
  \def\cal@datesplit#1-#2-#3-#4#5#6{#5#1:#2:#3:}

  \def\cal@Xdateexpand#1{\expandafter\cal@datesplit#1--\cal@ymd\cal@md\empty}

上面的版本“几乎”实现了我想要的(它可以工作,但如果调用参数包括一些其他宏调用,则会失败)。

如果我使用以下定义

\def\cal@Ydateexpand#1{\edef\cal@arg{#1}\expandafter\cal@datesplit\cal@arg--\cal@ymd\cal@md\empty}

即使使用其他宏作为参数调用该宏,它也能起作用。

我的第一个问题是,是否有另一种方法可以确保#1在调用之前将其展开\cal@datesplit?我原以为\expandafter\cal@datesplit#1这样就足够了……

现在,真正困扰我的问题是。当我尝试在另一个宏的定义中使用这两个宏时,使用\edef,第一个定义\cal@Xdateexpand“可以”,但第二个定义\cal@Ydateexpand编译失败。

下面是显示所有内容的最小代码...我想知道为什么它甚至无法编译(下面的情况 B.7 和 B.8)?

我正在使用 MiKTeX 2.9.7347。

\documentclass{article}

\makeatletter

            \def\cal@ymd#1:#2:#3:{#1-#2-#3}
            \def\cal@md#1:#2:#3:{\cal@Year-#1-#2}
            \def\cal@datesplit#1-#2-#3-#4#5#6{#5#1:#2:#3:}

            \def\cal@Xdateexpand#1{\expandafter\cal@datesplit#1--\cal@ymd\cal@md\empty}

            \def\cal@Ydateexpand#1{\edef\cal@arg{#1}\expandafter\cal@datesplit\cal@arg--\cal@ymd\cal@md\empty}

\def\cal@Year{2020}


\begin{document}
\def\dateMD{03-01} $\backslash$dateMD :: (\dateMD)

\def\dateYMD{2021-03-01} $\backslash$dateYMD :: (\dateYMD)

\def\dateY{2020} $\backslash$dateY :: (\dateY)

%% Using the \cal@X macro
A.1 (X) 03-01 :: (\cal@Xdateexpand{03-01})

A.2 (X) 2020-03-01 :: (\cal@Xdateexpand{2020-03-01})

A.3 (X) $\backslash$dateMD :: (\cal@Xdateexpand{\dateMD})

A.4 (X) 2020-$\backslash$dateMD :: (\cal@Xdateexpand{2020-\dateMD}) -- fails%% it fails in this case

A.5 (X) $\backslash$dateYMD :: (\cal@Xdateexpand{\dateYMD})

A.6 (X) $\backslash$dateY-$\backslash$dateMD :: (\cal@Xdateexpand{\dateY-\dateMD}) -- fails %% it fails in this case

%%
A.7 (X) edef 2020-03-01 :: \edef\SOME{\cal@Xdateexpand{2020-03-01}} (\SOME) 

A.8 (X) edef 2020-$\backslash$dateMD :: \edef\SOME{\cal@Xdateexpand{2020-\dateMD}} (\SOME) -- fails but compile%% it still fails, but compiles


%% Using the \cal@Y macro
B.1 (Y) 03-01 :: (\cal@Ydateexpand{03-01})

B.2 (Y) 2020-03-01 :: (\cal@Ydateexpand{2020-03-01})

B.3 (Y) $\backslash$dateMD :: (\cal@Ydateexpand{\dateMD})

B.4 (Y) 2020-$\backslash$dateMD :: (\cal@Ydateexpand{2020-\dateMD}) -- desired behaviour % This is the intended behaviour

B.5 (Y) $\backslash$dateYMD :: (\cal@Ydateexpand{\dateYMD})

B.6 (Y) $\backslash$dateY-$\backslash$dateMD :: (\cal@Ydateexpand{\dateY-\dateMD}) -- desired behaviour

%% the two edef below fails to compile, with a "missing control sequence inserted"
%B.7 (X) edef 2020-03-01 :: \edef\SOME{\cal@Ydateexpand{2020-03-01}} (\SOME) -- fails to compile

%B.8 (X) edef 2020-$\backslash$dateMD :: \edef\SOME{\cal@Ydateexpand{2020-\dateMD}} (\SOME) -- fails to compile


\end{document}

答案1

也许这就是你要找的东西。那么你根本\expanded不需要这个方法。\edef

\documentclass{article}

\makeatletter

            \def\cal@ymd#1:#2:#3:{#1-#2-#3}
            \def\cal@md#1:#2:#3:{\cal@Year-#1-#2}
            \def\cal@datesplit#1-#2-#3-#4#5#6{#5#1:#2:#3:}

            \def\cal@Xdateexpand#1{\expandafter\cal@datesplit
              \expanded{#1}--\cal@ymd\cal@md\empty}

            \def\cal@Ydateexpand#1{\edef\cal@arg{#1}\expandafter\cal@datesplit
              \cal@arg--\cal@ymd\cal@md\empty}

\def\cal@Year{2020}


\begin{document}
\def\dateMD{03-01} $\backslash$dateMD :: (\dateMD)

\def\dateYMD{2021-03-01} $\backslash$dateYMD :: (\dateYMD)

\def\dateY{2020} $\backslash$dateY :: (\dateY)

%% Using the \cal@X macro
A.1 (X) 03-01 :: (\cal@Xdateexpand{03-01})

A.2 (X) 2020-03-01 :: (\cal@Xdateexpand{2020-03-01})

A.3 (X) $\backslash$dateMD :: (\cal@Xdateexpand{\dateMD})

A.4 (X) 2020-$\backslash$dateMD :: (\cal@Xdateexpand{2020-\dateMD}) -- fails%% it fails in this case

A.5 (X) $\backslash$dateYMD :: (\cal@Xdateexpand{\dateYMD})

A.6 (X) $\backslash$dateY-$\backslash$dateMD :: (\cal@Xdateexpand{\dateY-\dateMD}) -- fails %% it fails in this case

%%
A.7 (X) edef 2020-03-01 :: \edef\SOME{\cal@Xdateexpand{2020-03-01}} (\SOME) 

A.8 (X) edef 2020-$\backslash$dateMD :: \edef\SOME{\cal@Xdateexpand{2020-\dateMD}} (\SOME) -- fails but compile%% it still fails, but compiles


%% Using the \cal@Y macro
B.1 (Y) 03-01 :: (\cal@Ydateexpand{03-01})

B.2 (Y) 2020-03-01 :: (\cal@Ydateexpand{2020-03-01})

B.3 (Y) macro dateMD :: (\cal@Ydateexpand{\dateMD})

B.4 (Y) 2020-macro dateMD :: (\cal@Ydateexpand{2020-\dateMD}) -- desired behaviour % This is the intended behaviour

B.5 (Y) macro dateYMD :: (\cal@Ydateexpand{\dateYMD})

B.6 (Y) macros dateY-dateMD :: (\cal@Ydateexpand{\dateY-\dateMD}) -- desired behaviour

%% the two edef below fails to compile, with a "missing control sequence inserted"
%B.7 (X) edef 2020-03-01 :: \edef\SOME{\cal@Ydateexpand{2020-03-01}} (\SOME) -- fails to compile

%B.8 (X) edef 2020-macro dateMD :: \edef\SOME{\cal@Ydateexpand{2020-\dateMD}} (\SOME) -- fails to compile


\end{document}

在此处输入图片描述

答案2

您可以使用expl3,更直接。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\calendardate}{m}
 {
  \alceu_calendar_date:e { #1 }
 }

\cs_new:Nn \alceu_calendar_date:n
 {
  \__alceu_calendar_date:w #1 - - \q_stop
 }
\cs_generate_variant:Nn \alceu_calendar_date:n { e }

\cs_new:Npn \__alceu_calendar_date:w #1 - #2 - #3 - #4 \q_stop
 {
  \tl_if_empty:nT { #3 } { \calYear - }
  #1 - #2
  \tl_if_empty:nF { #3 } { - #3 }
 }

\ExplSyntaxOff

\def\calYear{2020}


\begin{document}

\def\dateMD{03-01} \verb|\dateMD| :: (\dateMD)

\def\dateYMD{2021-03-01} \verb|\dateYMD| :: (\dateYMD)

\def\dateY{2020} \verb|\dateY| :: (\dateY)

A.1 (X) 03-01 :: (\calendardate{03-01})

A.2 (X) 2020-03-01 :: (\calendardate{2020-03-01})

A.3 (X) \verb|\dateMD| :: (\calendardate{\dateMD})

A.4 (X) 2020-\verb|\dateMD| :: (\calendardate{2020-\dateMD})

A.5 (X) \verb|\dateYMD| :: (\calendardate{\dateYMD})

A.6 (X) \verb|\dateY|-\verb|\dateMD| :: (\calendardate{\dateY-\dateMD})

A.7 (X) edef 2020-03-01 :: \edef\SOME{\calendardate{2020-03-01}} (\SOME) 

A.8 (X) edef 2020-\verb|\dateMD| :: \edef\SOME{\calendardate{2020-\dateMD}} (\SOME)

\end{document}

在此处输入图片描述

进行一点小改动以确保月份和日期都以两位数打印,与输入无关。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\calendardate}{m}
 {
  \alceu_calendar_date:e { #1 }
 }

\cs_new:Nn \alceu_calendar_date:n
 {
  \__alceu_calendar_date:w #1 - - \q_stop
 }
\cs_generate_variant:Nn \alceu_calendar_date:n { e }

\cs_new:Npn \__alceu_calendar_date:w #1 - #2 - #3 - #4 \q_stop
 {
  \tl_if_empty:nT { #3 } { \calYear - }
  \alceu_calendar_two:n { #1 } - \alceu_calendar_two:n { #2 }
  \tl_if_empty:nF { #3 } { - #3 }
 }

\cs_new:Nn \alceu_calendar_two:n
 {
  \int_compare:nT { \tl_count:n { #1 } < 2 } { 0 } #1
 }

\ExplSyntaxOff

\def\calYear{2020}


\begin{document}

\def\dateMD{3-1} \verb|\dateMD| :: (\dateMD)

\def\dateYMD{2021-3-01} \verb|\dateYMD| :: (\dateYMD)

\def\dateY{2020} \verb|\dateY| :: (\dateY)

A.1 (X) 03-01 :: (\calendardate{03-01})

A.2 (X) 2020-03-01 :: (\calendardate{2020-03-01})

A.3 (X) \verb|\dateMD| :: (\calendardate{\dateMD})

A.4 (X) 2020-\verb|\dateMD| :: (\calendardate{2020-\dateMD})

A.5 (X) \verb|\dateYMD| :: (\calendardate{\dateYMD})

A.6 (X) \verb|\dateY|-\verb|\dateMD| :: (\calendardate{\dateY-\dateMD})

A.7 (X) edef 2020-03-01 :: \edef\SOME{\calendardate{2020-03-01}} (\SOME) 

A.8 (X) edef 2020-\verb|\dateMD| :: \edef\SOME{\calendardate{2020-\dateMD}} (\SOME)

\end{document}

相关内容