我正在尝试将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
其中一个意外空格来自 之后的行尾\begin{foo}
,另一个来自 之后的行尾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 团队的待办事项清单上。
答案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
答案4
坦白说,我不知道整个包重写后它是否还能正常工作,但至少现在我能理解发生了什么。有几个限制:定义的环境只有两个参数。#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}