生存还是毁灭——宏定义中的可选参数

生存还是毁灭——宏定义中的可选参数

以下示例中的版本 A 部分是header/footer通过包中的宏来定义的fancyhdr

虽然这个版本是可行的,但是这是一个令人尴尬的成就,因为同一部分代码(\ifnum...)被写了两次。

除了可选参数 #2 之外,其他代码完全相同。为了改进它,我尝试了下面的版本 B,但它根本不起作用。

尤其是当同一部分代码很大时,这将是可怕的。

因此,总而言之,是否有更好的方法来处理可选参数(存在或不存在)以避免大量重复代码。

\documentclass{article}
\usepackage{geometry,fancyhdr,xparse}
\geometry{showframe}

\begin{document}
first page\par\vspace{80em} second page
\pagestyle{fancy}
\fancyhf{}

%Version A: workable %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentCommand{\firstpage}{momm}{%
  \IfNoValueTF{#2}
  {#1{%
      \ifnum\value{page}=1
      #3% content of header/footer only at the first page
      \else
      #4% content of header/footer at the rest pages
      \fi
    }
  }
  {#1[#2]% the only diferrence between the two branches of \IfNoValueTF is, whether introducing the optional argument #2
    {%
      \ifnum\value{page}=1
      #3% content of header/footer only at the first page
      \else
      #4% content of header/footer at the rest pages
      \fi
    }
  }
}%\firstpage

% Test
\firstpage{\fancyhead}[c]{only at the first page}{at rest pages}
\firstpage{\rhead}{r first}{r rest}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Version B: not workable %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentCommand{\firstpageA}{momm}{%
   #1 \IfNoValueTF{#2}{}{[#2]}
      \ifnum\value{page}=1
      #3% content of header/footer only at the first page
      \else
      #4% content of header/footer at the rest pages
      \fi
}%\firstpageA

% Test
\firstpageA{\fancyhead}[c]{only at the first page}{at rest pages}
\firstpageA{\rhead}{r first}{r rest}  

\end{document}

在此处输入图片描述

答案1

我认为尝试将不合适的语法融入这样的命令是没有用的。

花点时间设计一个更友好的语法会更有价值。我建议

\sethf{
  head = <contents of all headers, except possibly the first>,
  foot = <contents of all footers, except possibly the first>,
  pos = <l|c|r>,
  first = <possible exception for first header/footer>,
}

在 的调用中,只能使用head或中的一个。foot\sethf

\documentclass{article}
\usepackage{fancyhdr,xparse}

\usepackage[paper=a6paper]{geometry} % smaller pictures
\usepackage{lipsum} % mock text

\pagestyle{fancy}
\fancyhf{}

\ExplSyntaxOn
\NewDocumentCommand{\sethf}{m}
 {
  \tl_clear:N \l__lyl_hf_pos_tl
  \tl_clear:N \l__lyl_hf_first_tl
  \tl_clear:N \l__lyl_hf_headfoot_tl
  \keys_set:nn { lyl/hf } { #1 }
  \lyl_hf_set:
 }

\keys_define:nn { lyl/hf }
 {
  head  .code:n   = \__lyl_hf_aux:Nn \fancyhead { #1 },
  foot  .code:n   = \__lyl_hf_aux:Nn \fancyfoot { #1 },
  pos   .tl_set:N = \l__lyl_hf_pos_tl,
  first .tl_set:N = \l__lyl_hf_first_tl,
 }

\tl_new:N \l__lyl_hf_headfoot_tl

\cs_new_protected:Nn \__lyl_hf_aux:Nn
 {
  \cs_set_eq:NN \__lyl_hf_temp:w #1
  \tl_set:Nn \l__lyl_hf_headfoot_tl { #2 }
 }

\cs_new_protected:Nn \lyl_hf_set:
 {
  \tl_if_empty:NT \l__lyl_hf_first_tl
   {
    \tl_set_eq:NN \l__lyl_hf_first_tl \l__lyl_hf_headfoot_tl
   }
  \__lyl_hf_set:NVVV 
   \__lyl_hf_temp:w        % \fancyhead or \fancyfoot
   \l__lyl_hf_pos_tl       % position
   \l__lyl_hf_first_tl     % first page
   \l__lyl_hf_headfoot_tl  % other pages
 }
\cs_new_protected:Nn \__lyl_hf_set:Nnnn
 {
  #1 [ #2 ] { \int_compare:nTF { \value{page} = 1 } { #3 } { #4 } }
 }
\cs_generate_variant:Nn \__lyl_hf_set:Nnnn { NVVV }
\ExplSyntaxOff

\sethf{
  head = other pages,
  first = first page,
  pos = c,
}

\sethf{pos = r, foot=\thepage}

\begin{document}

\lipsum[1-2]

\end{document}

在此处输入图片描述

回答您的问题:使用宏来获取重复的代码。

\documentclass{article}
\usepackage{fancyhdr,xparse}

\usepackage[paper=a6paper]{geometry} % smaller pictures
\usepackage{lipsum} % mock text

\pagestyle{fancy}
\fancyhf{}

\NewDocumentCommand{\firstpage}{momm}{%
  \IfNoValueTF{#2}
   {\setfirstpage{#1}{#3}{#4}}
   {\setfirstpage{#1[#2]}{#3}{#4}}%
}
\NewDocumentCommand{\setfirstpage}{mmm}
 {
  #1{\ifnum\value{page}=1 #2\else #3\fi}
 }

\firstpage{\fancyhead}[c]{first page}{other pages}
% can also be \firstpage{\chead}{first page}{other pages}

\begin{document}

\lipsum[1-2]

\end{document}

可能用以下定义替换此处

\ExplSyntaxOn

\NewDocumentCommand{\firstpage}{momm}
 {
  \exp_last_unbraced:Nf #1 \IfNoValueTF{#2}{}{[#2]}
   {
    \int_compare:nTF { \value{page}=1 } { #3 } { #4 } 
   }
 }

\ExplSyntaxOff

但这不是我自己会做的事情。代码\IfNoValueTF{#2}{}{[#2]}可以更简单地替换为\IfValueT{#2}{[#2]}

答案2

对于具体的例子,\thispagestyle在第一页简单地使用可能会更好,但对于一般的问题,你可以避免预扫描参数,直到可选参数的测试之后,而辅助宏可以避免代码重复:

\documentclass{article}
\usepackage{geometry,fancyhdr,xparse}
\geometry{showframe}

\begin{document}
first page\par\vspace{80em} second page
\pagestyle{fancy}
\fancyhf{}


\def\fpageTF#1#2#3{#1{\ifnum\value{page}=1 #2\else #3\fi}}



\NewDocumentCommand{\firstpage}{mo}{%
  \IfNoValueTF{#2}{\fpageTF{#1}}{\fpageTF{#1[#2]}}}


% Test
\firstpage{\fancyhead}[c]{only at the first page}{at rest pages}
\firstpage{\rhead}{r first}{r rest}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{document}

相关内容