Разделение макросов на отдельные токены/символы с помощью catcode (для отладки условных выражений)?

Разделение макросов на отдельные токены/символы с помощью catcode (для отладки условных выражений)?

Рассмотрим этот 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 - и я получаюточно такой жесодержимое печатается, а условие все равно не срабатывает. Что я могу сделать, чтобы отладить такую ​​ситуацию?

Другими словами, есть ли какая-то функция, которую я мог бы использовать, которая (похожа наГенерация таблицы catcode в Latex (с \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 ?)

... чтобы у меня была возможность самому сделать вывод, почему равенство «строки» (макроса) не выполняется?

(Кстати, подвопрос: может ли макрос/команда/токен/управляющая последовательность (то есть то, что начинается с \) иметь кокод или нет?)

решение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 никогда не встречаются в теле макроса. А управляющие последовательности (токены без категории) выражены здесь как категория 16 для простого использования \showcatGв \ifnumтестах.

Связанный контент