如何使用不带包的 if 语句比较字符串?

如何使用不带包的 if 语句比较字符串?

例如,

\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(字母)不同的地方,而Acatcode 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}

在此处输入图片描述

相关内容