例如,
\newenvironment{genPage}[2]
{\clearpage\thispagestyle{#1}\normalsize\bfseries
\if#2=c
\centering
\fi
}
{\newpage}
\begin{document}
\begin{genPage}{plain}{c}
Some text...
\end{genPage}
\end{document}
很明显,我想做的事已经被理解了……提前致谢
编辑:抱歉,我还有一个问题。当我将环境参数留空时,宏 \pagestyle{empty}、\centering、\bfseries 也适用
\newenvironment{genPage}[3]{%
\clearpage
{%
\newcommand{\tempmacroe}{\detokenize{e}}%
\newcommand{\tempmacroE}{\detokenize{#1}}%
\newcommand{\tempmacrob}{\detokenize{b}}%
\newcommand{\tempmacroB}{\detokenize{#3}}%
\newcommand{\tempmacroc}{\detokenize{c}}%
\newcommand{\tempmacroC}{\detokenize{#2}}%
\expandafter
}%
\ifx\tempmacroe\tempmacroE
\thispagestyle{empty}
\fi
\ifx\tempmacrob\tempmacroB
\bfseries
\fi
\ifx\tempacroc\tempacroC
\centering
\fi
}{\newpage}
答案1
语法如下
\genPage{}{}{}
并不是我所说的好的用户界面,但它是您的文档。
\newenvironment{genPage}[3]
{%
\clearpage
\edef\tempmacroe{\detokenize{e}}%
\edef\tempmacroE{\detokenize{#1}}%
\edef\tempmacrob{\detokenize{b}}%
\edef\tempmacroB{\detokenize{#3}}%
\edef\tempmacroc{\detokenize{c}}%
\edef\tempmacroC{\detokenize{#2}}%
\ifx\tempmacroe\tempmacroE
\thispagestyle{empty}%
\fi
\ifx\tempmacrob\tempmacroB
\bfseries
\fi
\ifx\tempacroc\tempacroC
\centering
\fi
}
{\clearpage}
在执行零件之前打开的组\newcommand
是错误的,因为在执行测试时\tempmacroX
会忘记宏的值。\expandafter
你拥有的组什么也没做。
由于环境本身形成一个组,因此\tempmacroX
一旦\end{genPage}
执行,的值就会被遗忘。
请注意,使用\newcommand{\tempmacroe}{\detokenize{e}}
和类似的可以工作,但\detokenize
不会起作用:在第一个测试中,您将比较\tempmacroe
和的替换文本,\tempmacroE
这将是
\detokenize{e}
和
\detokenize{#1}
(和#1
实际参数替换),因此测试将失败如果您碰巧遇到一个没有类别代码 11 的e
论点。e
使用\detokenize
(但带有\edef
)将确保参数中使用的字符的类别代码无关紧要。
如果参数始终是一个标记,则不同的测试也可以起作用:
\if\detokenize{e}\detokenize{#1}\relax
\pagestyle{empty}
\fi
这不需要定义\tempmacroe
和\tempmacroE
。如果参数为空,\if
则将e
与进行比较\relax
。
你pdflatex
也可以这样做
\ifnum\pdfstrcmp{e}{#1}=0
\pagestyle{empty}%
\fi
它也独立于类别代码,并且具有允许
\newcommand{\thisisane}{e}
\begin{genPage}{\thisisane}{}{}
将选择\pagestyle{empty}
,因为的参数已\pdfstrcmp
扩展。
答案2
只要删除=
符号,否则 TeX 将尝试#2
比较=
:
\documentclass{article}
\newenvironment{genPage}[2]
{\clearpage\thispagestyle{#1}\normalsize\bfseries
\if c#2%
\centering
\fi
}
{\newpage}
\begin{document}
\begin{genPage}{plain}{notc}
Some text...
\end{genPage}
\begin{genPage}{plain}{c}
Some text...
\end{genPage}
\begin{genPage}{plain}{notcagain}
Some text...
\end{genPage}
\end{document}
正如 jfbu 指出的那样,环境因 而失败\begin{genPage}{plain}{cagain}
,导致输出居中(可能不应该),并且排版again Some text...
。但很明显你知道这一点 ;)
也许更安全的方法是执行与以下令牌比较\ifx
:
\newenvironment{genPage}[2]
{\clearpage\thispagestyle{#1}\normalsize\bfseries
{% group to restore tempmacroa and tempmacrob to whatever they were before
\def\tempmacroa{c}%
\def\tempmacrob{#2}%
\expandafter}%
\ifx\tempmacroa\tempmacrob
\centering
\fi
}
{\newpage}
或者,正如约瑟夫所建议的,使用以下方法进行字符串比较\detokenize
:
\newenvironment{genPage}[2]
{\clearpage\thispagestyle{#1}\normalsize\bfseries
{%
\edef\tempmacroa{\detokenize{c}}%
\edef\tempmacrob{\detokenize{#2}}%
\expandafter}%
\ifx\tempmacroa\tempmacrob
\centering
\fi
}
{\newpage}
答案3
您的代码\detokenize
从未执行过。您使用它的目的是什么?
右括号后面的空行产生一个\par
-token,并且该\expandafter
-token 应用于该空行。
你也许可以做类似的事情
\newenvironment{genPage}[3]{%
\clearpage
{%
\def{\tempmacroe}{e}%
\def{\tempmacroE}{#1}%
\def{\tempmacrob}{b}%
\def{\tempmacroB}{#3}%
\def{\tempmacroc}{c}%
\def{\tempmacroC}{#2}%
\def\tempmacro{}%
\ifx\tempmacroe\tempmacroE
\expandafter\def\expandafter\tempmacro\expandafter{\tempmacro\thispagestyle{empty}}%
\fi
\ifx\tempmacrob\tempmacroB
\expandafter\def\expandafter\tempmacro\expandafter{\tempmacro\bfseries}%
\fi
\ifx\tempacroc\tempacroC
\expandafter\def\expandafter\tempmacro\expandafter{\tempmacro\centering}%
\fi
\expandafter}\tempmacro
}{\newpage}
正如您尝试使用代码片段所做的那样,比较两个任意括号平衡标记序列的最直接方法是将它们分别用作⟨替换文本⟩另一个临时宏并\ifx
与临时宏进行比较:
\documentclass{article}
\makeatletter
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\DeclareRobustCommand\UnexpandableCheckWhetherTokenSequencesAreEqual[2]{%
\begingroup
\def\UD@tempa{#1}%
\def\UD@tempb{#2}%
\expandafter\endgroup
\ifx\UD@tempa\UD@tempb
\expandafter\UD@firstoftwo
\else
\expandafter\UD@secondoftwo
\fi
}%
\makeatother
\begin{document}
\UnexpandableCheckWhetherTokenSequencesAreEqual{Foo}{Bar}%
{Token sequences are equal.}%
{Token sequences are differing.}
\UnexpandableCheckWhetherTokenSequencesAreEqual{Foo}{Foo}%
{Token sequences are equal}%
{Token sequences are differing}
\end{document}
陷阱:
像这样的例程不能在扩展上下文中使用,\edef
或者\csname..\endcsname
因为(重新)定义临时宏意味着执行分配,而代表分配的标记不会在扩展阶段执行。
在定义之后\def\macro{A}
,A
和\macro
被视为不同的东西,尽管扩展会产生相同的标记序列。
显式字符标记被视为与隐式吊坠不同的东西。
例如,catcode 11(字母)的字符标记将被视为与通过定义的A
隐式字符标记不同的东西。\A
\let\A=A
一个 catcode 的显式字符标记被视为与不同 catcode 的显式挂件不同的东西。
例如,A
由于 catcode 12(其他)的原因,它可能出现在\string A
与 catcode 11(字母)不同的地方,而A
catcode 11(字母)可能是由于读取输入并标记一个A
字符而产生的。
对于可扩展地比较标记序列,其中只有一个在编写比较例程时尚未指定,并且其中指定的标记序列不包含括号/不包含类别代码 1 或 2 的明确字符标记,则\if
根本不需要 TeX' -原语。
您可以使用带有分隔参数的宏来实现这一点,使用那些已经指定为参数分隔符的字符串:
\documentclass{article}
\makeatletter
%%----------------------------------------------------------------------
%% Paraphernalia
%%----------------------------------------------------------------------
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
%%----------------------------------------------------------------------
%% 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\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Check whether argument does not contain "!":
%%......................................................................
\newcommand\UD@GobbleToExclam{}%
\long\def\UD@GobbleToExclam#1!{}%
\newcommand\UD@CheckWhetherNoExclam[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToExclam#1!}%
}%
%%----------------------------------------------------------------------
%% Implement Forking depending on the argument holding specific strings:
%%......................................................................
%% For showing the gist of the mechanism, let's crank out the cases of
%% the argument being empty, of the argument being "AAA", of the
%% argument being "BBB", of the argument being "CCC", of the argument
%% being "DDD", of the argument being "EEE", of the argument being
%% something else.
\newcommand\UD@StringFork{}%
\long\def\UD@StringFork#1!!AAA!BBB!CCC!DDD!EEE!#2#3!!!!{ #2}%
%%
\newcommand\StringFork[1]{%
\romannumeral0%
\UD@CheckWhetherNoExclam{#1}{%
\UD@StringFork
!#1!AAA!BBB!CCC!DDD!EEE!{Tokens in case argument is empty.}%
!!#1!BBB!CCC!DDD!EEE!{Tokens in case argument is AAA.}%
!!AAA!#1!CCC!DDD!EEE!{Tokens in case argument is BBB.}%
!!AAA!BBB!#1!DDD!EEE!{Tokens in case argument is CCC.}%
!!AAA!BBB!CCC!#1!EEE!{Tokens in case argument is DDD.}%
!!AAA!BBB!CCC!DDD!#1!{Tokens in case argument is EEE.}%
!!AAA!BBB!CCC!DDD!EEE!{Tokens in case argument is something else that contains no exclamation mark.}%
!!!!%
}{%
Tokens in case argument is something else that contains an exclamation mark.%
}%
% The "Tokens in case..."-thingies can, e.g., be provided as arguments #2..#9 of
% \StringFork.
%
% It is also feasible to let the "Tokens in case..."-thingies be numbers.
%
% When doing this, you can place the call to the \StringFork-macro as
% <numberK>-argument within the call to a macro
% \getKthArgumentOfLArguments{<numberK>}{<numberL>}%
% {Argument 1}%
% {Argument 2}%
% ...
% {Argument L}%
% where L can be larger than 10.
%
% When doing this, you can place the call to the \StringFork-macro as
% <number>-argument within an \ifcase<number> ..\or ..\or ... \else...\fi-statement.
}%
\makeatother
\parindent=0pt\relax
\begin{document}
\medskip\verb|\StringFork{!AAA!BBB!CCC!DDD!EEE!}|:\\
\StringFork{!AAA!BBB!CCC!DDD!EEE!}
\medskip\verb|\StringFork{AAA}|:\\
\StringFork{A{A}A}
\medskip\verb|\StringFork{FooBar}|:\\
\StringFork{FooBar}
\medskip\verb|\StringFork{ }|:\\
\StringFork{ }
\medskip\verb|\StringFork{}|:\\
\StringFork{}
\medskip\verb|\StringFork{AAA}|:\\
\StringFork{AAA}
\medskip\verb|\StringFork{BBB}|:\\
\StringFork{BBB}
\medskip\verb|\StringFork{CCC}|:\\
\StringFork{CCC}
\medskip\verb|\StringFork{DDD}|:\\
\StringFork{DDD}
\medskip\verb|\StringFork{EEE}|:\\
\StringFork{EEE}
\end{document}