使用连接宏的输出判断 \ifx 条件中的字符串相等性

使用连接宏的输出判断 \ifx 条件中的字符串相等性

请考虑以下 MWE - 我尝试测试参数和宏准备的测试字符串之间的字符串相等性:

\documentclass{article}

\def\testStr#1{IOIO#1}

\newcommand{\doTest}[1]{%
\edef\tmphwp{\testStr{XX}} %
\typeout{=\tmphwp=#1=} %
\ifx\tmphwp#1{%
\typeout{~equal}%
}\else{%
\typeout{!not equal}%
}\fi %
\typeout{ ^^J } % newline in terminal stdout
}

\begin{document}

\doTest{12}

\doTest{hello}

\doTest{IOIOXX}

\end{document}

奇怪的是,这似乎总是确定字符串不平等 - 即使我输入了正确的字符串 - 终端日志(来自pdflatex)报告:

=IOIOXX=12=
!not equal


=IOIOXX=hello=
!not equal


=IOIOXX=IOIOXX=
!not equal

嗯...我已经预料到了IOIOXX= IOIOXX?!

有人能解释一下为什么我没有得到预期的结果 - 以及如何进行正确的比较吗?这可能与 catcodes 有关吗?

非常感谢您的任何回答,
干杯!

答案1

需要注意的是\ifx无需扩大它们,后面跟着两个记号。现在我们慢慢看看 \dotest{IOIOXX}扩展为什么。

  1. \edef\tmphwp{\testStr{XX}}这相当于\def\tmphwp{IOIOXX}

  2. \typeout{=\tmphwp=#1=}打印在屏幕上=IOIOXX=IOIOXX=

  3. 条件

    \ifx\tmphwp IOIOXX{%
      \typeout{~equal}%
    }\else{%
      \typeout{!not equal}%
    }\fi %
    \typeout{ ^^J } % newline in terminal stdout
    

这是错误的,因为\tmphwp不同于I

你还犯了其他一些错误:你编写代码的方式留下了相当多的虚假空间;条件的真分支和假分支是不是需要放在括号中,但在大多数情况下这甚至是错误的。

为了比较两个字符串,该怎么做?将作为参数给出的字符串放入临时宏的替换测试中:

\def\dotest#1{%
  \def\next{#1}%
  \ifx\tmphwp\next
    \typeout{EQUAL}%
  \else
    \typeout{NOT EQUAL}%
  \fi
}

您已经在某处设置了\tmphwp扩展到“控制字符串”(我不明白为什么您应该在进行测试时设置它),例如

\def\tmphwp{IOIOXX}

假设\tmphwp扩展为IOIOXX:现在\ifx将比较两个控制序列\tmphwp以及\next哪个相等,因为它们都不相等\long,它们的参数文本相同(空)并且它们具有相同的替换文本(IOIOXX)。

相反,\dotest{AA}则会将测试评估为错误。

答案2

好的,解决了,感谢tex core - 检测参数文本中的 catcode - TeX - LaTeX; 尤其来自@HendrikVogt 的这条注释

这与 \fooA 或 \fooB 的 catcode 无关。\ifx 测试只是看到两个宏的参数文本不同(它们包含不同的 @),因此结果为负。\ifx 测试并不关心差异是什么。

...这意味着,然而,与“变量”(命令)的“字符串内容”字符的 catcode 有关... 以及以下\detokenize代码片段@杰森最终将这一切落实到位。

我经常遇到的另一个问题是,有时当我这样做时,\detokenize{\command}在 an 中说\edef,然后尝试\typeout输出 - 而不是内容的字符,我\command再次看到(显然理解为单个标记)。@Jason 对 \expandafter 的使用让我终于意识到应该写这样的结构:

   \edef\tpmx{\expandafter\detokenize\expandafter{\mycommand}}

...第一个\expandafter“转义” \detokenize- 并且第二个转义{花括号- 这样\mycommand可以首先将其扩展为它的内容; 并且\detokenize可以对内容的字符(变量值)进行操作。(但请注意,在以下节 \detokenize上工作时,无需进行这样的转义#1\edef\tmphwb{\detokenize{#1}}似乎工作得很好

因此,简而言之 - 它是关于 catcodes 的(我猜);并且一旦我们必须比较我们期望应该具有相同(ASCII)内容的字符串,但不知何故最终得到不同的 catcodes(来自不同的宏) - 那么我们可以\detokenize在比较之前调用“重置”两个字符串的字符的 catcode - 然后\ifx可以看到比较有效:

=IOIOXX=12=IOIOXX=12=
!not equal
!not equal
!not equal


=IOIOXX=hello=IOIOXX=hello=
!not equal
!not equal
!not equal


=IOIOXX=IOIOXX=IOIOXX=IOIOXX=
!not equal
!not equal
\~equal

上述pdflatex终端输出是通过对 OP MWE 代码进行以下修改而产生的:

\documentclass{article}

\def\testStr#1{IOIO#1}

\newcommand{\doTest}[1]{%
\edef\tmphwp{\testStr{XX}} %
\edef\tmphwb{\detokenize{#1}} %
% \edef\tmphwc{\detokenize{\tmphwp}} % NO: outputs \tmphwp!
% to have \detokenize{\tmphwp} show
%  actual content as expected here,
%  MUST use two \expandafter's:
%   one to skip \detokenize, and other to skip the
%   brace; - so \tmphwp can be expanded first!
\edef\tmphwc{\expandafter\detokenize\expandafter{\tmphwp}} %
\typeout{=\tmphwp=#1=\tmphwc=\tmphwb=} %
%
\ifx\tmphwp#1{%
  \typeout{\~equal}%
}\else{%
  \typeout{!not equal}%
}\fi %
%
\ifx\tmphwp\tmphwb{%
  \typeout{\~equal}%
}\else{%
  \typeout{!not equal}%
}\fi %
%
\ifx\tmphwc\tmphwb{%
  \typeout{\~equal}%
}\else{%
  \typeout{!not equal}%
}\fi %
\typeout{ ^^J } % newline in terminal stdout
}

\begin{document}

\doTest{12}

\doTest{hello}

\doTest{IOIOXX}

\end{document}

好吧,希望这对某人有帮助,
干杯!

相关内容