expl3
環境の内容に関数を適用しようとしています。LaTeX2e では\bgroup
、 とを使用してこれを実現できます\egroup
。 ではexpl3
、何かが機能しません。
次のコードは「AAA hey BBB」と出力されるはずです。 代わりに「AAA BBB hey」と出力されます。
\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}
なぜこのようなことが起こるのか、また回避策はあるのか、何かご意見はありますか?
編集
これが私の現在のアプローチです:
\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
\group_begin: と \group_end: は関数の引数をキャプチャするために使用できないため、これは機能しません (つまり、\foo \group_begin: A \group_end:
とは異なる動作をします\foo { A }
)。
制御シーケンスを、明示的な中括弧であるかのように一時的に強制的に動作させる方法はありますか?
解決策
解決策があると思います。コメントで述べたように、パターンマッチングと\begin
sの数を数えることを組み合わせて環境の内容をキャプチャすることができます。これが私にとって少し意外なことでした。正確にenviron
のすぐ下で何が起こっているのか多く表記法の。
意図したアプリケーションで が失敗したことはわかっているのでenviron
、コードのどこで失敗しているのかを突き止められるように、できるだけ単純な方法で を再実装することにしました (何が間違っていたのかはわかっていますが、それは重要ではありません)。 以下に での実装を示しますexpl3
。十分にテストしたわけではありませんが、動作すると思います。
どのようなコメントやレビューでも大歓迎です。
\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}
答え1
それは一度もない\bgroup
とで引数を取得することは可能でした\egroup
。バージョン
\newenvironment{foo}{%
\baz\bgroup
}{%
\egroup
}
\newcommand{\baz}[1]{AAA #1 BBB}
全く同じように失敗する。 の引数は\baz
なので\bgroup
、 の出力は
x\begin{foo}
key
\end{foo}y
だろう
xAAA<space><space>BBB<space>key<space>y
予期しないスペースの 1 つは の後の行末から発生し\begin{foo}
、もう 1 つは の後の行末から発生しますkey
。
environ
Christian Hupfer が示したように、を使用することもできます。
\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
そして、上記のコードの出力は予想通り
xAAA<space>key<space}BBBy
\NewEnviron
と同様の機能を追加することは、xparse
LaTeX チームの ToDo リストに載せる必要があります。
答え2
environ
これは、とを使用して、の で定義されたラッパー環境内で を\NewEnviron
キャッチして適用する方法です。つまり、- 引数指定子のすべての機能を引き続き使用できます。\BODY
xparse
\NewDocumentEnvironment
xparse
\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}
答え3
\bar:n
コンテンツを取得するために環境で使用したいことはわかっています。そのため、置換テキストを先にスキャンして\end
、\end
置換テキストの最後に再度挿入するだけです。
\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}
答え4
正直に言うと、パッケージ全体を書き直したら動作するかどうかはわかりませんが、少なくとも今は何が起きているのかは理解できます。いくつかの制限があります。定義された環境には 2 つのパラメータしかありません。#1 は環境の内容を表します。#2 は角括弧パラメータを表します。これは原理的にはキー値を含めるために使用できるため、この制限を克服できます。
さらに、私の環境では、コマンド \xbegin{\foo} と \xend{\foo} が動作します。これらのコマンドの基本的な構造は LaTeX 環境のものとは異なるため、別のキーワードを使用することにしました。いずれにせよ、このアプローチを拡張して LaTeX 環境に適用できると思います。
コードに関するレビューやコメントは大歓迎です!
\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}