为什么我不能用 \par 比较字符串?

为什么我不能用 \par 比较字符串?

首先:该包xstring无法识别 a\par作为参数。例如,当我这样做时:

\usepackage{xstring}

\def\apar{\par}
\def\str{a string}

\IfStrEq{\str}{\par}{% true part
}{% false part
}

这会导致错误。为什么专门为字符串制作的包没有对此进行检查,我不知道。


检查字符串是否等于的另一种方法\par是使用\ifx,但这也有限制。请看以下示例:

\def\apar{\par}
\def\str{\par}

First case:\\
\ifx\str\apar  % compare \str with a variable
  Str is a par.
\else
  Str is not a par.
\fi
\par
Second case:\\
\ifx\str\par  % compare \str with \par
  Str is a par.
\else
  Str is not a par.
\fi

输出结果如下:

第一种情况:
Str 是一个 par

第二种情况:
Str 不是 par

并不是说我对此有意见,只是我只是在问自己为什么会这样……

答案1

宏可以用前缀来定义\long(默认情况下是这样\newcommand),因此\par允许在其参数中使用(如果有)。否则\par不被接受并会引发错误。

特别是\IfStrEq围绕\@xs@IfStrEq@@它构建的软件包作者决定不这样做\long

我会非常谨慎使用\IfStrEq从文件读入的内容(我想这就是您想要测试读入的行是否为空的操作):如果该行包含任意命令,则执行的完整扩展\IfStrEq可能会导致灾难;例如,如果\textbf出现在该行中,完整扩展将惨遭失败。

当你这样做

\read\file to \fline

并且该行包含foo\bar baz,这相当于

\def\fline{foo\bar baz }

(注意尾随空格)。如果该行是空的,则变为

\def\fline{\par}

(因为 TeX 就是这样解释空行的)。这就是为什么“空”可以通过以下方式测试:

\def\apar{\par}
\ifx\fline\apar

因为\ifx测试宏的第一级展开是否相同(当标记不是宏时有更多规则,但在这种情况下它们是)。

如果你喜欢类似的语法\IfStrEq,那么你可以定义

\makeatletter
\newcommand\IfEmptyLine[1]{%
  \ifx#1\apar
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\makeatother

并将其用作

\IfEmptyLine{\fline}{<code for the empty case>}{<code for the nonempty case}

为什么会\ifx\apar\par返回 false?答案就在我之前没有提到的规则之一中。第一个标记是一个宏(用 定义\def),而\par是一个 TeX 基元(实际上它可以被重新定义,LaTeX 有时会这样做,但可以相当安全地假设在文档的正常部分中\par具有基元含义)。宏和基元是绝不被认为是相等的\ifx,因为前者有第一级扩展而后者没有。

如果\par重新定义,测试将再次返回 false,除非一位狡猾的程序员曾说过\def\par{\par}。虽然这可能在非常特殊情况下,您可以放心地认为,当您读取文件时它不会生效,因为独立的\par令牌会导致恶性循环,只有拔掉插头才能停止。

相关内容