Immer wieder stößt man auf den „\romannumeral-Trick“: man nützt die Tatsache aus, dass \romannumeral auf der Suche nach einer Zahl alles expandiert, bis es auf einen nicht-expandierbaren Token stößt, aber selbst zu nichts expandiert, wenn die sich ergebende Zahl negativ ist:

\documentclass{article}
\begin{document}
\def\a{\b}\def\b{\c}\def\c{\d}\def\d{1}
\expandafter\show\romannumeral-`\0\a
\end{document}

zeigt im Log:

> the character 1.
<recently read> 1

l.4 \expandafter\show\romannumeral-`\0\a

Das funktioniert, weil \romannumeral nach -`\0 -- obwohl eigentlich eine komplette Zahl -- weiter nach einem Leerzeichen schaut. (Diese Art der Expansion heißt bei expl3 (der LaTeX3-Programmierumgebung) f-type-Expansion.)

Soweit so gut. Was mir allerdings nicht klar ist: wozu oder wann braucht man diese Art der Expansion? Was sind praktische Beispiele, wo sie eingesetzt wird oder sogar eingesetzt werden muss? (Es scheint ja eine Art „expandierbarer Expansion“ zu sein?)

gefragt 26 Jul '13, 21:56

cgnieder's gravatar image

cgnieder
22.1k253463
Akzeptiert-Rate: 60%

bearbeitet 04 Aug '13, 21:50

Sehr oft stößt man IMHO nicht auf den Trick. Im Prinzip zeigt Dein eigenes Beispiel bereits, wofür er gut ist. Wollte man etwas ähnliches ohne den Trick machen, müsste man ein Hilfemakro mit \edef definieren und darauf \show anwenden.

Ich nehme aber an, dass eine der häufigeren Anwendung das Entfernen von Leerzeichen ist. AFAIK nutzen beispielsweise trimspaces und verschiedene key=value-Pakete das.

(27 Jul '13, 08:20) saputello

Das Entfernen von Leerzeichen ist ein guter Hinweis, Danke. An die hatte ich gar nicht gedacht, obwohl ich's ja noch erwähnt hatte... Bei meinem eigenen Beispiel leuchtet mir noch nicht ganz ein, wo der potentielle Vorteil gegenüber einem Hilfsmakro und \edef wäre.

(27 Jul '13, 09:37) cgnieder

@Clemens Da es bei TeX scopes nur in Form von Gruppen, nicht aber beispielsweise zur Trennung unterschiedlicher Module/Pakete/Klassen (oder wie immer man es nennen mag) gibt, sind Hilfsmakros immer ein wenig lästig, weil man keine wirklich privaten Namen dafür hat. Gerade das Verpacken in Gruppen kann höchst lästig sein, wenn man das Ergebnis dann wieder außerhalb der Gruppe benötigt. Man landet da sehr schnell bei seltsamen Konstrukten mit \expandafter, \unexpanded, \noexpand und \aftergroup. Deshalb sind Tricks, die Hilfsmakros und damit auch Gruppen vermeiden, oftmals nützlich.

(31 Jul '13, 13:55) saputello

@Herbert Danke für den Link! @saputello Ok, das leuchtet mir ein. Selbst mit hinreichend langen und komplizierten Namen für Hilfsmakros ist man natürlich nie vollständig auf der sicheren Seite. Dennoch scheint mir -- je weiter ich mich damit beschäftige -- der eigentliche Vorteil darin zu liegen, dass die \romannumeral-Expansion selbst expandierbar ist, z.B.:

\def\cdr#1{\expandafter\@cdr\romannumeral-`\0#1\@nil}
\edef\tmp{\cdr{\cdr{test}}}
(31 Jul '13, 15:39) cgnieder

Versuch einer Eigenantwort nach verschiedenen Recherchen (und inzwischen auch eigener Anwendung)...


Grundsätzlich scheint es für die \romannumeral-Expansion (oder f-Expansion) drei Einsätze zu geben:

  1. Entfernen von führenden Leerzeichen.
  2. Volles Expandieren (von links) auf expandierbare Art, d.h., in einem \edef o.ä. anwendbar. Auch von Nutzen, wenn man nicht weiß, wie viele Expansionen bötigt werden und wie lang eine expandafter-Kette sein müsste.
  3. Bilden einer Schleife.

Punkte 2. und 3. scheinen häufiger eingesetzt zu werden als der erste Punkt.

Für Punkt 1. habe ich quasi keine Hinweise gefunden, dass es tatsächlich in der Praxis angewendet wird, abgesehen von dem einen oder anderen Post von Heiko Oberdiek auf TeX.sx. Das Prinzip ist einfach (hier steht · für eine beliebige Anzahl Leerzeichen):

Open in writeLaTeX
\romannumeral·<num>·\relax

und

Open in writeLaTeX
\romannumeral<num>\relax

sind äquivalent: nach Befehlssequenzen werden Leerzeichen sowieso ignoriert und das Leerzeichen nach <num> (mehrere Leerzeichen verhalten sich wie eines) wird von \romannumeral (wie auch von anderen TeX Primitiven, die nach Zahlen suchen) verwendet, um das Ende der Zahl festzustellen, und dann weggeworfen.

Beispiel:

Open in writeLaTeX
\documentclass{article}
\begin{document}
\makeatletter
\long\def\trim@left#1{\romannumeral-`\q#1}
\def\foo{      foo }

!\trim@left{\foo}!
\end{document}

Punkt 2. scheint öfter verwendet zu werden, um expandierbar Makros zu expandieren. Wenn man z.B. aufmerksam auf TeX.sx sucht, findet man dafür immer wieder Beispiele. Auch in Paketen wird es angewendet, etwa dem trimspaces-Paket. Im wesentlichen definiert es einen Befehl \trim@spaces wie folgt:

Open in writeLaTeX
\catcode`\Q=3
\newcommand\trim@spaces[1]{%
  \romannumeral-`\q\trim@trim@\noexpand#1Q Q%
}
\long\def\trim@trim@#1 Q{\trim@trim@@#1Q}
\long\def\trim@trim@@#1Q#2{#1}
\catcode`\Q=11

\romannumeral expandiert von links, d.h., wie wenn man eine genügende Menge \expandafters verwendet hätte. Es wird also zunächst \trim@trim@ expandiert, was rechts die Leerzeichen entfernt, dann wird \trim@trim@@ expandiert, was das zweite Q3 entfernt, dann wird \noexpand expandiert, was schließlich linke Leerzeichen entfernt, da sie hinter \noexpand ignoriert werden1. Da es reicht, \romannumeral zu expandieren, um den gesamten Mechanismus zu starten und zu Ende zu bringen, kann das Paket nun zum Beispiel recht einfach einen Befehl definieren, das die Leerzeichen entfernt, den Rest aber unexpandiert zurücklässt:

Open in writeLaTeX
\newcommand\trim@spaces@noexp[1]{%
  \unexpanded\expandafter\expandafter\expandafter{\trim@spaces{#1}}%
}

Punkt 3. wird zum Beispiel in den \xx_case: Funktionen von expl3 ausgenützt, Joseph Wright hat das hier ganz gut erklärt. Auch das Paket multiexpand nützt die gleiche Methode. Hier wird ausgenützt, dass \romannumeral auf der Suche nach einer Zahl und folgendem Leerzeichen weiterexpandiert, aber aufhört, wenn es das gefunden hat. Hier wird eine 0 mit folgendem Leerzeichen gefüttert, um aus der Schleife auszubrechen. Im folgenden Beispiel (der Definition von \MultiExpand aus eben genanntem Paket) macht das das Makro \ME@endroman. Gleichzeitig braucht der schleifende Befehl (kann man das so sagen?) selbst nur eine Expansion! Im Beispiel unten bedeutet das, dass zweifache Expansion von \MultiExpand (damit \romannumeral getriggert wird) die achtfache (!) Expansion von \a liefert:

Open in writeLaTeX
\documentclass{article}
\begin{document}
\makeatletter
\def\ME@use#1{#1}%
\def\MultiExpand{\romannumeral\multiexpand}%
\edef\ME@endroman#1{0\noexpand\expandafter\space}%
\long\def\multiexpand#1{%
  \ifnum#1<2
    \expandafter\ME@endroman
  \else
    \expandafter\ME@use
  \fi
  {%
    \expandafter\multiexpand
    \expandafter{\number\numexpr#1-1\expandafter}%
  }%
}%

\def\a{\b}
\def\b{\c}
\def\c{\d}
\def\d{\e}
\def\e{\f}
\def\f{\g}
\def\g{\h}
\def\h{\i}
\def\i{\j}
\def\j{k}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\x
\expandafter\expandafter\expandafter{\MultiExpand{8}\a}
\show\x % ->\i .

\end{document}

Ich selber habe mir inzwischen angewöhnt, sie für Punkt 2., die expandierbare Expansion, einzusetzen.


  1. Ich hoffe, diese Analyse ist korrekt. Auch hier bitte ich um eventuelle Berichtigung.
Permanenter link

beantwortet 04 Aug '13, 20:30

cgnieder's gravatar image

cgnieder
22.1k253463
Akzeptiert-Rate: 60%

bearbeitet 17 Mai '14, 18:40

Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×52
×22
×7

gestellte Frage: 26 Jul '13, 21:56

Frage wurde gesehen: 10,948 Mal

zuletzt geändert: 17 Mai '14, 18:40