
Wenn ich das Rautezeichen/Nummernzeichen/Hash-Zeichen #
in Befehlen und Umgebungen verwende, bezieht sich dies auf Argumente. Es sollte jedoch nicht \detokenize{#}
dazu führen , dassNICHTein Argument?
Situation
Das Nummernzeichen dient als praktische Trennlinie in Protokolldateien.
Beispiel
Versuchen Sie, das zweite Kommentarfeld zu entfernen, \detokenize
um eine Fehlermeldung zu erhalten.
\documentclass{article}
\usepackage{fontspec}% compile with xelatex
\newenvironment{detokenizetest}[1]
{% firstoftwo
\detokenize{##############################################################################}%
%\detokenize{##BEGIN#######################################################################}% uncommenting this causes a compile error
}%
{% secondoftwo
}%
\begin{document}
\null
\end{document}
Fehlerausgabe
Dieser Fehler tritt nur auf, wenn die Zeile, die enthält, auskommentiert wird BEGIN
.
! Illegal parameter number in definition of \detokenizetest.
<to be read again>
}
l.9 }
%
?
Antwort1
Da #
es den Kategoriecode 6 hat, hat es in TeX eine ganz besondere Bedeutung, weil es zur Bezeichnung von Parametern in Makrodefinitionen verwendet wird.
Die Regeln von TeX besagen, dass Sie, wenn Siespeicherna #
im Ersetzungstext eines Makros, müssen Sie es verdoppeln.
Bei der Verarbeitung des Ersetzungstextes für eine Makrodefinition #
muss auf eine einzelne Ziffer eine Ziffer (1 bis 9) folgen, die einen Zeiger auf das entsprechende Argument bezeichnet, wobei ##
als gespeichert wird #
. Mit diesem Trick können Sie so etwas wie
\def\foo{\def\baz##1{-##1-}}
Der Ersetzungstext von \foo
ist daher \def\baz#1{-#1-}
und ein Aufruf von \foo
wird \baz
als Makro mit einem einzigen Argument definiert.
Das Primitiv \detokenize
im Ersetzungstext wird seine Arbeit verrichtenwenn das Makro aufgerufen und erweitert wird, nicht zum Definitionszeitpunkt, es sei denn, die Definition erfolgt mit \edef
, wodurch zunächst eine vollständige Erweiterung durchgeführt wird, bevor der Ersetzungstext im Speicher abgelegt wird.
Beachten Sie, dass Ihnen in diesem Fall \meaning\foo
(unter der Annahme der obigen Definition) Folgendes angezeigt wird:
macro:->\def \baz ##1{-##1-}
und das gleiche wird passieren, \detokenize
wenn der gleiche Mechanismus verwendet wird. Also so etwas wie
\edef\hashmarks{\detokenize{####}}
#
wird tatsächlich zwei im Ersetzungstext sehen , aber das Endergebnis wird vier davon sein. Der Standardmechanismus bei der Verarbeitung \edef
halbiert zunächst die Anzahl #
und \detokenize
verdoppelt sie dann wieder. Insbesondere SiekippenErzeugen Sie auf diese Weise eine ungerade Anzahl von #
.
Wenn Sie Trennlinien erstellen möchten, ist es viel besser, eine indirekte Methode zu verwenden und im Voraus die erforderliche Tokenliste bestehend aus #
mit dem Kategoriecode 12 zu erstellen. Im Beispiel verwende ich drei davon, nur weil es eine ungerade Zahl ist.
\documentclass{article}
\begingroup\lccode`?=`# \lowercase{\endgroup
\newcommand{\lineofhashsigns}{???}
}
\newenvironment{delimitedtext}
{\par\lineofhashsigns\par}
{\par\lineofhashsigns\par}
\begin{document}
\begin{delimitedtext}
abc
\end{delimitedtext}
\end{document}
Eine andere Definition hierfür ist \lineofhashsigns
nicht erforderlich, \lowercase
indem der Kategoriecode geändert wird:
\catcode`#=12
\newcommand{\lineofhashsigns}{###}
\catcode`#=6
Sie können im Ersetzungstext beliebige Token hinzufügen, solange das Makro keine Argumente enthalten soll.
Antwort2
Das \detokenize
Primitiv bedeutet in der Tat, dass #
nicht als Parameter behandelt wird, sondern als einer, wenn es erweitert wird. Denken Sie daran, dass bei einer normalen Zuweisung ( \newcommand
in LaTeX \def
als TeX-Primitiv) keine Erweiterung stattfindet. Hier \newenvironment
wird genau dasselbe „einfach speichern“ der Token durchgeführt wie \newcommand
. Dies bedeutet, dass wir die übliche TeX-Regel haben, dass wir beim Erstellen eines Makros die passenden Parameter für jedes vorhanden haben müssen #
oder die Token verdoppelt werden müssen #
.
Da \newenvironment
sich letztendlich ein ergibt \def
, können wir mit folgendem tun, was Sie möchten \edef
:
\edef\detokenizetest#1{%
\detokenize{##############################################################################}%
\detokenize{##BEGIN#######################################################################}%
}
\def\enddetokenizetest{}% As \newenvironment will do this
\show\detokenizetest