expl3
Ich versuche, eine Funktion auf den Inhalt einer Umgebung anzuwenden . In LaTeX2e kann dies durch die Verwendung von \bgroup
und erreicht werden \egroup
. In expl3
funktioniert etwas nicht.
Ich würde erwarten, dass der folgende Code „AAA hey BBB“ ausgibt. Stattdessen wird „AAA BBB hey“ ausgegeben.
\ExplSyntaxOn
\cs_new:Npn \bar:n #1 {
AAA #1 BBB
}
\NewDocumentEnvironment{foo}{}{
\bar:n \bgroup
}{
\egroup
}
\ExplSyntaxOff
\begin{document}
\begin{foo}
hey
\end{foo}
\end{document}
Gibt es irgendwelche Ideen, warum das passiert und welche Problemumgehungen es gibt?
Bearbeiten
Dies ist mein aktueller Ansatz:
\cs_new:Npn \env_new:Nn #1#2 {
\tl_new:N #1
\tl_set:Nn #1 { #2 }
}
\cs_new:Npn \env_begin:N #1 {}
\cs_new:Npn \env_end:N #1 {}
\cs_new:Npn \env_capture_on: {
\global \let \env_begin:N \group_begin:
\global \let \env_end:N \group_end:
}
\cs_new:Npn \env_capture_off: {
\global\let\env_begin:N\env_original_begin:N
\global\let\env_end:N\env_original_end:N
}
\cs_new:Npn \env_original_begin:N #1 {
\env_capture_on:
\tl_use:N #1
\group_begin:
\env_capture_off:
}
\cs_new:Npn \env_original_end:N #1 {
}
\env_capture_off:
\cs_new:Npn \foo:n #1 {
AAA #1 BBB
}
\env_new:Nn \baf {
\foo:n
}
\env_begin:N \baf
hey
\env_end:N \baf
Dies funktioniert nicht, da \group_begin: und \group_end: nicht zum Erfassen von Funktionsargumenten verwendet werden können (d. h. \foo \group_begin: A \group_end:
anders funktioniert als \foo { A }
).
Gibt es eine Möglichkeit, eine Steuersequenz vorübergehend so zu zwingen, sich so zu verhalten, als wäre sie eine explizite Klammer?
Eine Lösung
Ich glaube, ich habe eine Lösung. Wie ich in den Kommentaren erwähnt habe, könnte man Mustervergleich mit dem Zählen der Anzahl von \begin
s kombinieren, um den Inhalt einer Umgebung zu erfassen. Es war ein wenig überraschend für mich, dass diesgenauwas ist los in environ
, knapp unter einemVIELder Notation.
Da ich weiß, dass dies environ
bei meiner beabsichtigten Anwendung fehlschlug, habe ich beschlossen, es auf möglichst einfache Weise neu zu implementieren, damit ich herausfinden kann, wo mein Code fehlschlägt (jetzt habe ich eine Idee, was schiefgelaufen ist, aber darum geht es nicht). Unten finden Sie eine Implementierung in expl3
. Ich habe sie nicht gründlich getestet, aber ich glaube, sie funktioniert.
Wir freuen uns über alle Kommentare und Bewertungen.
\int_new:N \env_count
\cs_new:Npn \env_new:Nn #1#2 {
\cs_new:cpn { env_defined@ \cs_to_str:N #1 :nn } ##1##2 {
#2
}
}
\cs_new:Npn \env_countbegin:w #1\xbegin#2 {
\cs_if_free:NTF #2 {
\int_incr:N \env_count
\env_countbegin:w
} {
\cs_if_eq:NNTF #2 \xend {} {
\int_incr:N \env_count
\env_countbegin:w
}
}
}
\cs_new:Npn \env_collect:w #1#2#3#4\xend#5 {
\env_countbegin:w #4\xbegin\xend
\int_compare:nTF { \env_count = 0 } {
\use:c { env_defined@ \cs_to_str:N #1 :nn } { #3 #4 } { #2 }
}{
\int_decr:N \env_count
\env_collect:w {#1} {#2} { #3 #4 \xend{#5} }
}
}
\NewDocumentCommand \xbegin {mo} {
\int_zero:N \env_count
\env_collect:w {#1} {#2} {}
}
\NewDocumentCommand \xend {} {}
\env_new:Nn \foo {
AAA #1 BBB
}
\xbegin{\foo}
\xbegin{\foo}
hey
\xend{\foo}
\xend{\foo}
Antwort1
Es hatniemals\bgroup
war es möglich, ein Argument mit und zu ergreifen \egroup
. Die Version
\newenvironment{foo}{%
\baz\bgroup
}{%
\egroup
}
\newcommand{\baz}[1]{AAA #1 BBB}
würde auf genau dieselbe Weise fehlschlagen. Das Argument für \baz
wäre \bgroup
, also die Ausgabe von
x\begin{foo}
key
\end{foo}y
wäre
xAAA<space><space>BBB<space>key<space>y
Eines der unerwarteten Leerzeichen stammt vom Zeilenende nach \begin{foo}
, das andere vom Zeilenende nach key
.
Es ist möglich, zu verwenden environ
, wie Christian Hupfer zeigt:
\usepackage{xparse,environ}
\ExplSyntaxOn
\NewEnviron{foo}
{
\jaeya_baz:V \BODY
}
\cs_new:Nn \jaeya_baz:n { AAA~#1~BBB }
\cs_generate_variant:Nn \jaeya_baz:n { V }
\ExplSyntaxOff
und die Ausgabe des obigen Codes wäre die erwartete
xAAA<space>key<space}BBBy
Das Hinzufügen ähnlicher Funktionen wie \NewEnviron
in xparse
sollte auf der To-Do-Liste des LaTeX-Teams stehen.
Antwort2
Dies ist eine Möglichkeit mit environ
und \NewEnviron
, es abzufangen \BODY
und innerhalb einer Wrapper-Umgebung anzuwenden, xparse
die mit definiert ist \NewDocumentEnvironment
, was bedeutet, dass alle Funktionen aus xparse
-Argumentbezeichnern weiterhin verwendet werden können.
\documentclass{article}
\usepackage{environ}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Nn \bar:n {
AAA #1 BBB
}
\NewEnviron{foointernal}{
\bar:n {\BODY}
}
\ExplSyntaxOff
\let\origfoointernal\foointernal
\let\origendfoointernal\endfoointernal
\NewDocumentEnvironment{foo}{}{%
\origfoointernal%
}{%
\origendfoointernal%
}
\begin{document}
\begin{foo}
hey
\end{foo}
\begin{foo}
\blindtext
Hello World
\end{foo}
\end{document}
Antwort3
Sie wissen, dass Sie eine Umgebung verwenden möchten, \bar:n
um den Inhalt abzurufen. Lassen Sie es also einfach vorausscannen \end
und \end
am Ende des Ersatztexts erneut einfügen.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \bar:n #1 \end {
AAA #1 BBB \end
}
\NewDocumentEnvironment{foo}{}{\bar:n}{}
\ExplSyntaxOff
\begin{document}
\begin{foo}
hey
\end{foo}
\end{document}
Antwort4
Ich weiß ehrlich gesagt nicht, ob es funktioniert, wenn das ganze Paket neu geschrieben ist, aber jetzt verstehe ich zumindest, was vor sich geht. Es gibt ein paar Einschränkungen: Definierte Umgebungen haben nur zwei Parameter. #1 stellt den Inhalt der Umgebung dar; #2 stellt einen Parameter in eckigen Klammern dar, der im Prinzip verwendet werden kann, um Schlüsselwerte zu enthalten und so diese Einschränkung zu überwinden.
Darüber hinaus arbeiten meine Umgebungen mit den Befehlen \xbegin{\foo} und \xend{\foo}. Die zugrunde liegende Struktur dieser Befehle unterscheidet sich von der der LaTeX-Umgebungen, daher habe ich mich entschieden, andere Schlüsselwörter zu verwenden. Ich vermute jedoch, dass der Ansatz erweitert werden könnte, um auf LaTeX-Umgebungen anwendbar zu sein.
Jede Bewertung oder jeder Kommentar zum Code ist herzlich willkommen und wird geschätzt!
\documentclass[10pt]{article}
\usepackage{expl3}
\ExplSyntaxOn
\int_new:N \env_count
\cs_new:Npn \env_new:Nn #1#2 {
\cs_new:cpn { env_defined@ \cs_to_str:N #1 :nn } ##1##2 {
#2
}
}
\cs_new:Npn \env_countbegin:w #1\xbegin#2 {
\cs_if_free:NTF #2 {
\int_incr:N \env_count
\env_countbegin:w
} {
\cs_if_eq:NNTF #2 \xend {} {
\int_incr:N \env_count
\env_countbegin:w
}
}
}
\cs_new:Npn \env_collect:w #1#2#3#4\xend#5 {
\env_countbegin:w #4\xbegin\xend
\int_compare:nTF { \env_count = 0 } {
\use:c { env_defined@ \cs_to_str:N #1 :nn } { #3 #4 } { #2 }
}{
\int_decr:N \env_count
\env_collect:w {#1} {#2} { #3 #4 \xend{#5} }
}
}
\NewDocumentCommand \xbegin {mo} {
\int_zero:N \env_count
\env_collect:w {#1} {#2} {}
}
\NewDocumentCommand \xend {} {}
\env_new:Nn \foo {
AAA #1 BBB
}
\ExplSyntaxOff
\begin{document}
\xbegin{\foo}
\xbegin{\foo}
hey
\xend{\foo}
\xend{\foo}
\end{document}