扩展宏的参数

扩展宏的参数

不管怎样,我使用以下代码定义了附录的页码:

\pagenumbering{arabic}\renewcommand{\thepage}{A.\arabic{page}}

foo如果我使用\label{foo}on page创建标签A.21,则对的调用将\pageref{foo}扩展到A.21文本中。最终,我想确定页码是奇数还是偶数。

我尝试创建一个宏,删除“A.”部分,只保留“21”。我尝试定义

\def \appnum A.#1 {#1}

来实现这一点。在文档中,命令

\appnum A.21

返回“21”,没有错误。但是,命令

\appnum \pageref{foo}

返回错误

! Use of \appnum doesn't match its definition.

我尝试了各种方法\expandafter\expand解决这个问题,例如

\expandafter\appnum\pageref{foo}

无济于事。

我的真实的问题是“我怎样才能从页码引用中去掉‘A’,以便命令\isodd可以确定页码是奇数还是偶数?”我思考如果有人解释如何让我的\appnum宏正确读取,\pageref我就可以从那里开始。

答案1

您可以使用\refcount

\documentclass{article}
\usepackage[paperwidth=6cm,paperheight=4cm,margin=2mm,includefoot]{geometry}
\usepackage{refcount}

\makeatletter
% we assume page numbers are either plain numbers or of the form A.<number>
\newcommand{\oddorevenpage}[1]{%
  % #1 = label for the page to check
  % #2 = text for odd page
  % #3 = text for even page
  \ifodd\expandafter\remove@A@prefix\expandafter{\romannumeral-`Q\getpagerefnumber{#1}}
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

\def\remove@A@prefix#1{\remove@A@prefix@aux A.#1A.#1A.\@nil}
\def\remove@A@prefix@aux A.#1A.#2A.#3\@nil{#2}

\makeatother

\begin{document}

x\label{odd}

\oddorevenpage{odd}{This page is odd}{This page is even}

\clearpage

x\label{even}

\oddorevenpage{even}{This page is odd}{This page is even}

\clearpage

\pagenumbering{arabic}
\renewcommand{\thepage}{A.\arabic{page}}

x\label{odd-app}

\oddorevenpage{odd-app}{This page is odd}{This page is even}

\clearpage

x\label{even-app}

\oddorevenpage{even-app}{This page is odd}{This page is even}

\clearpage

\setcounter{page}{21}

x\label{foo}

\oddorevenpage{foo}{This page is odd}{This page is even}

\end{document}

在此处输入图片描述

相同之处expl3

\documentclass{article}
\usepackage[paperwidth=6cm,paperheight=4cm,margin=2mm,includefoot]{geometry}
\usepackage{refcount}
\usepackage{xparse}

\ExplSyntaxOn
% we assume page numbers are either plain numbers or of the form A.<number>
\NewExpandableDocumentCommand{\oddorevenpage}{mmm}
 {% #1 = label for the page to check
  % #2 = text for odd page
  % #3 = text for even page
  \gregh_odd_even:fnn { \getpagerefnumber{#1} } { #2 } { #3 }
 }

\cs_new:Nn \gregh_odd_even:nnn
 {
  \int_if_odd:nTF { \gregh_remove_prefix:n { #1 } } { #2 } { #3 }
 }
\cs_generate_variant:Nn \gregh_odd_even:nnn { f }

\cs_new:Nn \gregh_remove_prefix:n
 {
  \__gregh_remove_prefix_aux:w A. #1 A. #1 A. \q_stop
 }

\cs_new:Npn \__gregh_remove_prefix_aux:w A. #1 A. #2 A. #3 \q_stop { #2 }

\ExplSyntaxOff

\begin{document}

x\label{odd}

\oddorevenpage{odd}{This page is odd}{This page is even}

\clearpage

x\label{even}

\oddorevenpage{even}{This page is odd}{This page is even}

\clearpage

\pagenumbering{arabic}
\renewcommand{\thepage}{A.\arabic{page}}

x\label{odd-app}

\oddorevenpage{odd-app}{This page is odd}{This page is even}

\clearpage

x\label{even-app}

\oddorevenpage{even-app}{This page is odd}{This page is even}

\clearpage

\setcounter{page}{21}

x\label{foo}

\oddorevenpage{foo}{This page is odd}{This page is even}

\end{document}

答案2

我刚刚删除了之前的回答。以下是重写的内容:

使用\ref/\pageref以可计算的方式获取数字并不是一个好主意:

原因:

-command\label确实省去了 的扩展\thepage。正如您自己所做的那样,\thepage可以重新定义为以阿拉伯数字形式传递不属于页面计数器值的标记。

许多软件包重新定义了引用命令,以传递非数字项。
例如超链接该包重新定义了引用命令,将标记嵌套在标记内形成数字值,从而使整个事物成为超链接。

另一个问题是:

我们以一份连续页面的排列文档为例。

通过\pagenumbering将页计数器的值重置为 0,并设置打印该值的方式。

在附录中将页码计数器重置为 0 之后,后续页面的页码计数器的值将不再是既表示该页面在文档所有页面排列中的位置的序数,又不再是用于命名页面的名义数字/名义值,而仅仅是名义数字/名义值。

例如,要检测页面是左侧页面还是右侧页面,仅查看标称数字/标称值可能还不够。因此海科·奥伯迪克在他的实施参考值打包模块隐藏页面:使用此模块,页码不仅在页计数器的计数寄存器中计数,而且还在另一个计数寄存器中计数,该计数寄存器在整个 LaTeX 运行过程中永远不会重置。通过这个其他计数寄存器引用页面在任何情况下都会表示相关页面在页面排列中的位置。

解决方案 1—我更喜欢这个,因为不需要对参考进行后处理来去除可能的前缀短语:

使用参考值包含模块的软件包abspage来自海科·奥伯迪克既具有另一个可引用属性,表示相关页面在文档所有页面排列中的位置,又可以根据需要引入新的可引用属性:

随着参考值基于下面的编码示例,

  • \RefPageCounterValueInArabic{foo}将以阿拉伯数字形式提供页面计数器的值,而不附加任何额外的内容,当 LaTeX 遇到相应的命令时,该计数器的值将发送到该页面\zlabel{foo}

  • \CheckWhetherPageCounterValueInArabicOdd{foo}{tokens if odd}{tokens if even}是一种根据该值是奇数还是偶数进行分支的方法。

  • \AbsolutePageref{foo}将会 — — 无论页码计数器如何重置,也无论页码样式如何更改 — — 都会告诉您在遇到相应的\zlabel{foo}命令时 LaTeX 即将构建的页面在文档所有页面的排列中是哪个元素。

  • \CheckWhetherAbsPageOdd{foo}{tokens if odd}{tokens if even}\AbsolutePageref{foo}当遇到相应的命令时,告诉您 LaTeX 即将构建的页面\zlabel{foo}n-文档所有页面排列的第个元素,然后\CheckWhetherAbsPageOdd{foo}{tokens if odd}{tokens if even}是一种根据奇偶校验进行分支的方法n

 

\documentclass{article}
\usepackage{hyperref}
\usepackage[user, abspage]{zref}

\makeatletter
\newcommand\MyRefUndefPhrase{%
  \nfss@text{\reset@font\bfseries??}%
}%
%
% Dealing with the value held in the page-counter's count-register:
%
\zref@newprop*{PageNumValueInArabic}[\MyRefUndefPhrase]{\arabic{page}}%
\zref@addprop{main}{PageNumValueInArabic}%
%
\newcommand\RefPageCounterValueInArabic[1]{%
  \zref@extractdefault{#1}{PageNumValueInArabic}{\MyRefUndefPhrase\refused{#1}}%
}%
\newcommand\CheckWhetherPageCounterValueInArabicOdd[1]{%
  \refused{#1}%
  \ifodd\zref@extractdefault{#1}{PageNumValueInArabic}{0} %<-This space must be!
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}%
%
% Dealing with the position of the page in question within the
% arrangement of all pages belonging to the document:
%
\newcommand\AbsolutePageref[1]{%
  \zref@extractdefault{#1}{abspage}{\MyRefUndefPhrase\refused{#1}}%
}%
\newcommand\CheckWhetherAbsPageOdd[1]{%
  \refused{#1}%
  \ifodd\zref@extractdefault{#1}{abspage}{0} %<-This space must be!
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}%
\makeatother    

\begin{document}
\section{page numbers without prefix}
Some text.\label{foo}\zlabel{foo}

\verb|\pageref{foo}|:
\pageref{foo}

\bigskip

\verb|\RefPageCounterValueInArabic{foo}|:
\RefPageCounterValueInArabic{foo}

\verb|\CheckWhetherPageCounterValueInArabicOdd{foo}{odd}{even}|:
\CheckWhetherPageCounterValueInArabicOdd{foo}{odd}{even}

\bigskip

\verb|\AbsolutePageref{foo}|:
\AbsolutePageref{foo}

\verb|\CheckWhetherAbsPageOdd{foo}{odd}{even}|:
\CheckWhetherAbsPageOdd{foo}{odd}{even}

\bigskip

\verb|\pageref{bar}|:
\pageref{bar}

\bigskip

\verb|\RefPageCounterValueInArabic{bar}|:
\RefPageCounterValueInArabic{bar}

\verb|\CheckWhetherPageCounterValueInArabicOdd{bar}{odd}{even}|:
\CheckWhetherPageCounterValueInArabicOdd{bar}{odd}{even}

\bigskip

\verb|\AbsolutePageref{bar}|:
\AbsolutePageref{bar}

\verb|\CheckWhetherAbsPageOdd{bar}{odd}{even}|:
\CheckWhetherAbsPageOdd{bar}{odd}{even}

\newpage

\pagenumbering{arabic}
\renewcommand{\thepage}{A.\arabic{page}}

\section{page numbers with prefix ``A.''}
Some text.\label{bar}\zlabel{bar}

\end{document}

第 1 页(共 2 页): 在此处输入图片描述

第 A.1 页(共 2 页): 在此处输入图片描述

解决方案 2:

如果在遇到相关命令时,只需获取 LaTeX 即将构建的页面的页面计数器的值\label就足够了,并且您不需要确切地知道该页面在属于文档的所有页面的排列中属于哪个元素,那么您可以使用\getrefbykeydefaultfrom海科·奥伯迪克引用计数包裹。

在下面的编码示例中,处理页码前面有“A.”的情况的方式可能看起来有点麻烦。它可扩展,并且没有标记标记,标记标记必须不出现在要检查的标记序列中。并且对其他前导短语实施检查很容易,因为您只需再调用\UD@internaltokencheckdefiner一次,就可以将各个部分组合在一起。

\documentclass{article}
\usepackage{hyperref}
\usepackage{refcount}

\makeatletter
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Exchange two arguments
%%......................................................................
\newcommand\UD@Exchange[2]{#2#1}%
%%----------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific 
%% token-sequence that does not contain explicit character tokens of 
%% category code 1 or 2:
%%......................................................................
%% \UD@CheckWhetherLeadingTokens{<a <token sequence> without explicit 
%%                                character tokens of category code 1 or 2>}%
%%                              {a <single non-space token> that does 
%%                                _not_ occur in <token sequence> >}%
%%                              {<internal token-check-macro>}%
%%                              {<argument which is to be checked>}%
%%                              {<tokens to be delivered in case <argument
%%                                which is to be checked> has <token sequence>
%%                                as leading tokens>}%
%%                              {<tokens to be delivered in case <argument
%%                                which is to be checked> does not have
%%                                <token sequence> as leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[4]{%
  \romannumeral0\UD@CheckWhetherNull{#4}%
  {\expandafter\expandafter\@firstoftwo{ }{}\@secondoftwo}%
  {\expandafter\@secondoftwo\string{\expandafter
   \UD@@CheckWhetherLeadingTokens#3#2#4#1}{}}%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
  {\UD@Exchange{\@firstoftwo}}{\UD@Exchange{\@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\@secondoftwo\expandafter{\string}%
}% 
%%----------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%%                              {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything 
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%......................................................................
\newcommand\UD@internaltokencheckdefiner[2]{%
  \newcommand#1{}\long\def#1##1#2{{##1}}%
}%
\UD@internaltokencheckdefiner{\UD@CheckADot}{A.}%
%%----------------------------------------------------------------------
%% Remove leading "A."
%%......................................................................    
\newcommand\removeAdot{}
\def\removeAdot A.{}
%%----------------------------------------------------------------------
%% Check for leading "A." and remove if present:
%%......................................................................    
\newcommand\removeAdotWhenPresent[1]{%
  \romannumeral0%
  \UD@CheckWhetherLeadingTokens{A.}%
                               {:}%
                               {\UD@CheckADot}%
                               {#1}%
                               {\@firstoftwo\expandafter{} \removeAdot}%
                               { }%
                               #1%
}%
%%----------------------------------------------------------------------
%% Textual phrase for undefined references
%%......................................................................    
\newcommand\MyRefUndefPhrase{%
  \nfss@text{\reset@font\bfseries??}%
}%
%%----------------------------------------------------------------------
%% Referencing-commands:
%%......................................................................    
\newcommand\RefPageCounterValueInArabic[1]{%
  \expandafter\expandafter\expandafter\removeAdotWhenPresent
  \expandafter\expandafter\expandafter{%
    \getrefbykeydefault{#1}{page}{A.\MyRefUndefPhrase\refused{#1}}%
  }%
}%
\newcommand\CheckWhetherPageCounterValueInArabicOdd[1]{%
  \refused{#1}%
  \ifodd
    \expandafter\expandafter\expandafter\removeAdotWhenPresent
    \expandafter\expandafter\expandafter{%
      \getrefbykeydefault{#1}{page}{A.0}%
    } %<-This space must be!
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}%
\makeatother

\begin{document}
\section{page numbers without prefix}
Some text.\label{foo}

\verb|\pageref{foo}|:
\pageref{foo}

\verb|\RefPageCounterValueInArabic{foo}|:
\RefPageCounterValueInArabic{foo}

\verb|\CheckWhetherPageCounterValueInArabicOdd{foo}{odd}{even}|:
\CheckWhetherPageCounterValueInArabicOdd{foo}{odd}{even}

\verb|\pageref{bar}|:
\pageref{bar}

\verb|\RefPageCounterValueInArabic{bar}|:
\RefPageCounterValueInArabic{bar}

\verb|\CheckWhetherPageCounterValueInArabicOdd{bar}{odd}{even}|:
\CheckWhetherPageCounterValueInArabicOdd{bar}{odd}{even}

\newpage

\pagenumbering{arabic}
\renewcommand{\thepage}{A.\arabic{page}}

\section{page numbers with prefix ``A.''}
Some text.\label{bar}

\end{document}

第 1 页(共 2 页): 在此处输入图片描述

第 A.1 页(共 2 页): 在此处输入图片描述

请注意,在任何情况下,第一次运行 LaTeX 时都尚未定义任何引用。第一次运行 LaTeX 时,所有引用(\pageref包括 -references)均未定义。

使用这两种解决方案时,第一次运行 LaTeX 时引用页计数器的值均假定为 0,并且在 .log 文件中发出有关未定义引用的警告以及需要重新运行 LaTeX。

相关内容