考虑这个 MWE,修改自ifthenelse 相等字符串比较失败:
\documentclass{article}
\edef\test{german\relax}
\edef\curentry{\string german\relax}
\typeout{test: \meaning\test, curentry: \meaning\curentry}
\ifx\curentry\test
\typeout{ equal}
\else
\typeout{ unequal}
\fi
\begin{document}
\end{document}
如果你用 编译它pdflatex test.tex
,你会在终端看到这个输出:
test: macro:->german\relax , curentry: macro:->german\relax
unequal
现在,链接的帖子解释了为什么会出现这种情况:
发生的情况是 \string 被应用于它看到的第一个标记,在本例中是 g。比较两个结果,它们是不一样的:一个有一个非字母然后有五个字母,第二个有六个字母。
但是,假设我尝试检查某种情况,在一个我不太清楚宏是如何定义的包中。所以我决定使用\typeout
宏\meaning
- 然后我得到了完全一样内容已打印,但条件仍然失败。我该如何调试这种情况?
换句话说,我可以使用某种函数吗?它(类似于在 Latex 中生成 catcode 表(使用 \typeout 到终端)?)将输出上述宏,例如:
% \typeoutComponents{\test}
g (catcode 11)
e (catcode 11)
r (catcode 11)
m (catcode 11)
a (catcode 11)
n (catcode 11)
\relax (catcode ?)
% \typeoutComponents{\curentry}
g (catcode 12)
e (catcode 11)
r (catcode 11)
m (catcode 11)
a (catcode 11)
n (catcode 11)
\relax (catcode ?)
...这样我就有机会自己推断为什么“字符串”(宏)相等会失败?
(顺便说一句,有一个子问题:宏/命令/标记/控制序列(即以 开头的东西\
)是否可以有 catcode?)
答案1
该命令\tl_analysis_show:N
按照您的要求执行。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\checktokenbytoken}{sm}
{
\IfBooleanTF{#1}
{
\tl_show_analysis:n { #2 }
}
{
\tl_show_analysis:N #2
}
}
\ExplSyntaxOff
\edef\xgerman{\string german\relax}
\checktokenbytoken{\xgerman}
\checktokenbytoken*{german\relax}
您将在终端上看到
The token list \xgerman contains the tokens:
> g (the character g)
> e (the letter e)
> r (the letter r)
> m (the letter m)
> a (the letter a)
> n (the letter n)
> \relax (control sequence=\relax).
<recently read> }
l.19 \checktokenbytoken{\xgerman}
?
The token list contains the tokens:
> g (the letter g)
> e (the letter e)
> r (the letter r)
> m (the letter m)
> a (the letter a)
> n (the letter n)
> \relax (control sequence=\relax).
<recently read> }
l.20 \checktokenbytoken*{german\relax}
(对于 TeX Live 2017 之前的版本,您还需要\usepackage{l3tl-analysis}
才能\usepackage{xparse}
使用此功能,并且\tl_show_analysis:N
现已弃用)
答案2
我的解决方案不需要任何外部包。\showcat\macro
已实现。之后
\def\test{ger{$##m}a~n \relax \foo}
\edef\curentry{\string german \relax}
\showcat\test
\showcat\curentry
我们得到结果:
\test ->
the letter g (catcode 11)
the letter e (catcode 11)
the letter r (catcode 11)
begin-group character { (catcode 1)
math shift character $ (catcode 3)
macro parameter character # (catcode 6)
the letter m (catcode 11)
end-group character } (catcode 2)
the letter a (catcode 11)
the token ~ (catcode 13)
the letter n (catcode 11)
blank space (catcode 10)
the token \relax (catcode 16)
the token \foo (catcode 16)
\curentry ->
the character g (catcode 12)
the letter e (catcode 11)
the letter r (catcode 11)
the letter m (catcode 11)
the letter a (catcode 11)
the letter n (catcode 11)
blank space (catcode 10)
the token \relax (catcode 16)
实施如下:
\def\showcat#1{\immediate\write16{\string#1 -> }\expandafter\showcatA#1\showcatA}
\def\showcatA{\futurelet\tmp\showcatB}
\def\showcatB{\let\next=\showcatE
\ifx\tmp\bgroup \let\next=\showcatC \fi
\ifx\tmp\egroup \let\next=\showcatC \fi
\expandafter\ifx\space\tmp \let\next=\showcatC \fi
\ifx\tmp\showcatA \let\next=\showcatF \fi
\next
}
\def\showcatC{\afterassignment\showcatD \let\tmp= }
\def\showcatD{\showcatE\tmp}
\def\showcatE#1{\edef\next{\string#1}%
\immediate\write16{\space\space
\ifnum\showcatG<13 \meaningtmp \else the token \next
\fi \space (catcode \showcatG)}%
\showcatA
}
\def\meaningtmp{\meaning\tmp}
\def\showcatF#1{}
\def\showcatG{\showcatH\bgroup1\showcatH\egroup2\showcatH$3\showcatH&4%
\showcatH##6\showcatH^7\showcatH_8\showcatH{ }{10}%
\showcatH A{11}\showcatH/{12}\showcatH~{13}16}
\def\showcatH#1#2{\ifcat\noexpand\tmp\noexpand#1#2\expandafter\showcatI\fi}
\def\showcatI#116{}
当然,类别为 0, 5, 9, 14, 15 的 token 在宏体中是不会出现的,而控制序列(没有类别的 token)为了\showcatG
在\ifnum
测试中简单使用,这里表示为类别 16。