Эквивалент \bgroup \egroup в LaTeX3

Эквивалент \bgroup \egroup в LaTeX3

Я пытаюсь применить 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 }).

Есть ли способ временно заставить управляющую последовательность вести себя так, как если бы она была явной фигурной скобкой?

Решение

Я думаю, у меня есть решение. Как я уже упоминал в комментариях, можно объединить сопоставление с образцом с подсчетом числа \begins, чтобы захватить содержимое окружения. Для меня было немного удивительно, что этоименно такчто происходит в 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, как показал Кристиан Хапфер:

\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

Это способ с environand \NewEnviron, перехватывающий \BODYи применяющий его в среде-оболочке, определенной с помощью xparse' s \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

Честно говоря, я не знаю, будет ли это работать, когда весь пакет будет переписан, но теперь я хотя бы понимаю, что происходит. Есть несколько ограничений: определенные среды имеют только два параметра. #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}

Связанный контент