使用catcode(以調試條件)將巨集拆分為單獨的標記/字元?

使用catcode(以調試條件)將巨集拆分為單獨的標記/字元?

考慮這個 MWE,修改自iftheelse 相等字串比較失敗

\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。比較兩個結果,它們不一樣:一個有 1 個非字母,然後有 5 個字母,第二個有 6 個字母。

但是,假設我嘗試在一個套件中檢查某些情況,但我並不真正知道巨集是如何定義的。所以我決定使用\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 的標記永遠不會出現在宏體中。為了\showcatG\ifnum測試中簡單使用,控制序列(沒有類別的標記)在這裡表示為類別 16。

相關內容