请考虑以下 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}
扩展为什么。
\edef\tmphwp{\testStr{XX}}
这相当于\def\tmphwp{IOIOXX}
\typeout{=\tmphwp=#1=}
打印在屏幕上=IOIOXX=IOIOXX=
条件
\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}
好吧,希望这对某人有帮助,
干杯!