输出不应显示的文本

输出不应显示的文本

我很困惑为什么下面的 MWE 会产生任何黑色文本。代码如下,输出为:

在此处输入图片描述

但是,如果您注释掉该\IfStrEq行,它就可以正常工作并且黑色文本会消失?

\documentclass{article}
\usepackage{xcolor}
\usepackage{xstring}
\usepackage{xparse}

\NewDocumentCommand{\GetTexFilePath}{m m m}{%
    \IfStrEq{#1}{SpecialValue}{}{}% this should do nothing
    %
    ../../../#1/#2/#3%
}%

\begin{document}
\def\FileWithPath{\GetTexFilePath{01}{02}{z}}%
\IfFileExists{\FileWithPath}{%
    \textcolor{red}{File \FileWithPath\ found.}%
}{%
    \textcolor{red}{File \FileWithPath\ not found.}%
}%
\end{document}

答案1

您的问题归结为\IfStrEq无法扩展,但\IfFileExist仍然试图扩展它。本质上,\IfFileExist执行以下操作:(#1是您的文件,此处\IfStrEq...

\openin\@inputcheck#1\relax % open the file
\ifeof\@inputcheck          % did the file exist?
  File exists.
\else
  \@iffileonpath {#1}       % search in \input@path
    {File exists.}{File doesn't exist.}
\fi

TeX 基元\openin将流号\@inputcheck作为其第一个参数,然后尽可能多地扩展,抓取文件名的字符,直到遇到空格(它会删除空格)或不可扩展的命令。如果文件名#1由字符组成,或者扩展为字符,则\openin找到的文件名会在 处停止\relax,并\IfFileExists搜索正确的文件。但是,在您的情况下,\FileWithPathTeX 会尽可能多地从左侧扩展,直到到达不可扩展的命令。在此阶段,没有遇到任何字符(如预期的那样:在实际开始进行测试\let之前没有排版任何内容),因此找到一个空文件名。\IfStrEq\openin

但整体\FileWithPath仍然存在,只是稍微扩展了一点。如您所料,\IfStrEq什么都没有排版,但路径的其余部分已排版。然后是测试\ifeof:由于您的 TeX 发行版包含一个文件.tex(您可以通过尝试找到它的路径\input\relax),空文件\openin已在流中打开该文件\@inputcheck,因此\ifeof测试为真。条件分支File found被采用,让我们认为一切都进展顺利。

那么……如何解决这个问题?例如,使用可扩展的字符串比较。无论如何,您通过 加载的包expl3(来自包)提供和应该适合您的需求(第一个在逐个字符比较它们之前像在 中一样扩展其参数;第二个不扩展)。要使用这样的“代码”命令,我们需要转到“Expl 语法”。l3kernelxparse\str_if_eq:xxTF\str_if_eq:nnTF\edef

\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\GetTexFilePath}{m m m}
  {
    \str_if_eq:xxTF{#1}{SpecialValue}{}{}
    ../../../#1/#2/#3
  }
\ExplSyntaxOff

\begin{document}
\def\FileWithPath{\GetTexFilePath{01}{02}{z}}%
\IfFileExists{\FileWithPath}{%
    \textcolor{red}{File \FileWithPath\ found.}%
}{%
    \textcolor{red}{File \FileWithPath\ not found.}%
}%
\end{document}

[编辑以替换\NewDocumentCommand\NewExpandableDocumentCommand即使前者恰好在这种情况下起作用,但一般来说,它定义了一个不可扩展的命令,并且通常不会扩展,让您回到这个答案第一部分描述的扩展问题。][重新编辑:Peter Grill 提到不\NewExpandableDocumentCommand存在。]

或者,您可以使用稍微奇怪的原语\pdfstrcmp(或者\strcmp在 XeTeX 中,或者在 LuaTeX 中,Heiko 提供的一些命令?),它接受两个参数(将它们扩展为\edef),并根据字符串的字典顺序扩展为 -1、0 或 1,如果它们相等则为 0。

编辑:鉴于你的进一步问题,我认为更简单的方法是在定义时“计算”完整路径,\FileWithPath而不是定义\FileWithPath计算路径。为此,请替换\def\FileWithPath{...}为对分配函数的调用\defTeXFilePath,该函数执行一些检查(可扩展或不可扩展),然后决定在中存储什么\FileWithPath。这里我选择了\tl_if_eq:nnTF而不是\str_if_eq:xxTF。区别:“tl”而不是“str”意味着我们正在比较标记及其字符代码和类别代码,而不是简单的字符串(我认为这是颜色与黑白);“n”而不是“x”意味着我们不执行扩展。请随意更改以满足您的需要。

\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\defTeXFilePath}{m m m m}
  {
    \tl_if_eq:nnTF{#2}{SpecialValue}
      { \tl_set:Nn #1 { ../../../#2/#3/#4 } }
      { \tl_set:Nn #1 { ../../../#2/xxx#3/#4 } }
  }
\ExplSyntaxOff

\begin{document}
\defTeXFilePath{\FileWithPath}{01}{02}{z}%
%\show\FileWithPath % see that \FileWithPath contains no macro call.
\IfFileExists{\FileWithPath}{%
    \textcolor{red}{File \FileWithPath\ found.}%
}{%
    \textcolor{red}{File \FileWithPath\ not found.}%
}%
\end{document}

相关内容