![Wie schreibt man ein Makro, das Argumente mit Absätzen annimmt?](https://rvso.com/image/391694/Wie%20schreibt%20man%20ein%20Makro%2C%20das%20Argumente%20mit%20Abs%C3%A4tzen%20annimmt%3F.png)
Ich versuche, ein Makro zu schreiben, das Argumente mit Absätzen akzeptiert. Wenn Sie ein normales Makro schreiben und eines seiner Argumente einen Absatz enthält, wird es unterbrochen:
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\def\mymacro#1{#1}
\mymacro{This
contains a paragraph}
\end{document}
Dies führt zu einem Fehler:
Runaway argument? {This ! Paragraph ended before \mymacro was complete. <to be read again> \par l.15
Also habe ich versucht, \par
die Argumente des Makros zum Erweitern neu zu definieren, aber jetzt wird die Kompilierung nicht mehr gestoppt:
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\gdef\oldpar{\par}
\def\mymacro{\gdef\par{}\mymacroi}
\def\mymacroi#1{#1\gdef\par{\oldpar}}
\mymacro{foo
bar}
\end{document}
Antwort1
Als TeX geschrieben wurde, dauerte die Verarbeitung einer Seite eines Dokuments mehrere Minuten und Syntaxhervorhebung war noch nicht möglich. Daher war es gut, einen Mechanismus zu haben, der erkennt, ob man ein vergessen hat }
. Ein \def
lässt standardmäßig kein \par
Token zu, es sei denn, man gibt explizit an, dass es ein ist \long\def
:
\def\mymacro#1{#1}
LaTeX hingegen verwendet dies standardmäßig. Wenn Sie also die richtigen LaTeX-Befehle verwenden ( \def
sollte nicht in LaTeX-Dokumenten verwendet werden), wird standardmäßig \newcommand
ein erstellt . Wenn Sie ein „kurzes“ möchten , verwenden Sie .\long\def
\def
\newcommand*
xparse
gibt das kurze Argument default zurück, ermöglicht Ihnen aber, ein \long
Makro mit dem +
Argumentmodifikator zu definieren:
\NewDocumentCommand\mymacro{ m}{#1}% \def
\NewDocumentCommand\mymacro{+m}{#1}% \long\def
Ihr zweiter Versuch ist geschickt und hätte funktionieren können, wenn da nicht zwei Dinge wären.
Zuerst verwenden Sie \gdef\oldpar{\par}
und dann\gdef\par{\oldpar}
. Sobald Sieexpandieren \par
Sie erhalten, \oldpar
was, wenn erweitert, ergibt, \par
was, wenn erweitert, ergibt, \oldpar
was, wenn erweitert, ergibt, \par
was, wenn erweitert, ergibt \oldpar
... Läuft ewig :/
In diesem Fall müssen Sie Folgendes verwenden \let
(oder um eine globale Wirkung zu erzielen): . Dadurch wird eine genaue Kopie von „named“ erstellt , die nicht davon abhängt, was „named“ ist .\global\let
\let\oldpar\par
\par
\oldpar
\par
Zweitens wird die Überprüfung auf außer Kontrolle geratene Argumente auf einer niedrigeren Ebene implementiert, unabhängig von der Definition von \par
, sodass dies mit demselben Fehler fehlschlagen würde:
\let\par\relax
\def\mymacro#1{#1}
\mymacro{foo
bar}
denn wenn TeX zwei \endlinechar
Token sieht (was standardmäßig ein Leerzeichen ist), fügt TeX ein implizites \par
Token ein, was den Runaway argument
Fehler auslöst. Wenn man das weiß, dann:
\newcount\oldELchar
\oldELchar=\endlinechar
\def\mymacro{\endlinechar=-1\relax\mymacroi}
\def\mymacroi#1{#1\endlinechar=\oldELchar}
\mymacro{foo
bar}
wird keinen Fehler auslösen, aber eine neue Zeile wird kein Leerzeichen mehr sein.
Antwort2
Das Argument eines mit definierten Makros \def
erlaubt keine \par
Token. Es erlaubt auch keine Leerzeilen, da diese \par
während der Phase, in der TeX Texteingaben in Tokens verarbeitet, in umgewandelt werden. Beachten Sie, dass eine Neudefinition \par
in dieser Hinsicht nutzlos ist, da esgenaudas Token \par
, das nicht zulässig ist, unabhängig von seiner Bedeutung.
Lösung: Erstellen Sie Ihr Makro \long
.
\long\def\mymacro#1{#1}
Bessere Lösung:
\newcommand{\mymacro}[1]{#1}
weil intern \newcommand
verwendet wird \long\def
. Die Variante \newcommand*
verwendet stattdessen \def
ohne das Präfix.