首先:该包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
令牌会导致恶性循环,只有拔掉插头才能停止。