%3F.png)
Considere este MWE, modificado deifthenelse comparação de string igual falha:
\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}
Se você compilar isso com pdflatex test.tex
, verá esta saída no terminal:
test: macro:->german\relax , curentry: macro:->german\relax
unequal
Agora, a postagem vinculada explica por que isso acontece:
o que acontece é que \string é aplicado ao primeiro token que ele vê, neste caso um g. Comparando os dois resultados, eles não são iguais: um tem uma não letra e depois cinco letras, o segundo tem seis letras.
Porém, digamos que eu tente inspecionar alguma situação, em um pacote onde não sei realmente como as macros foram definidas. Então eu decido usar \typeout
as \meaning
macros - e recebo oexatamente o mesmoconteúdo impresso e a condicional ainda falha. O que posso fazer para depurar esse tipo de situação?
Em outras palavras, existe algum tipo de função que eu poderia usar, que (semelhante aGerando uma tabela catcode em Latex (com \typeout para terminal)?) geraria as macros acima, digamos:
% \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 ?)
... para que eu tivesse a chance de deduzir por que uma igualdade de "string" (macro) falharia?
(Aliás, uma subquestão: uma sequência de macro/comando/token/controle (ou seja, a coisa que começa com \
) pode ter um código de gato ou não?)
Responder1
O comando \tl_analysis_show:N
faz o que você pede.
\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}
Você receberá, no terminal,
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}
(Para versões anteriores ao TeX Live 2017, você precisará \usepackage{l3tl-analysis}
de adicionais \usepackage{xparse}
para que isso funcione e \tl_show_analysis:N
, agora obsoleto)
Responder2
Minha solução não precisa de nenhum pacote externo. O \showcat\macro
está implementado. Depois
\def\test{ger{$##m}a~n \relax \foo}
\edef\curentry{\string german \relax}
\showcat\test
\showcat\curentry
obtemos o resultado:
\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)
E a implementação:
\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{}
Claro, os tokens com categoria 0, 5, 9, 14, 15 nunca ocorrem no corpo macro. E as sequências de controle (tokens sem categoria) são expressas aqui como categoria 16 para facilitar o uso \showcatG
em \ifnum
testes.