我想定义嵌套环境,这些环境具有相同的子命令和子环境嵌套定义。使用方法如下:
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenvb}
我希望myenvx
是一个完全不同的环境,在myenva
和下使用时具有不同的功能myenvb
。同样,我希望myenvz
之下与之下myenva/myenvx
完全不同。myenvz
myenvb/myenvx
我有以下 MWE 演示我如何尝试使其工作:
\documentclass[a4paper]{article}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\begin{document}
\NewDocumentEnvironment{myenva}{} {
\NewDocumentEnvironment{myenvx}{} {
\NewDocumentEnvironment{myenvz}{} {
\NewDocumentCommand{mycmdz} {
\mycmda{}
\mycmdx{}
\typeout{mycmdz}
}
}{}
\NewDocumentCommand{mycmdx} {
\typeout{mycmdx}
}
}{}
\NewDocumentCommand{mycmda} {
\typeout{mycmda}
}
}{}
\NewDocumentEnvironment{myenvb}{} {
\NewDocumentEnvironment{myenvx}{} {
\NewDocumentEnvironment{myenvz}{} {
\NewDocumentCommand{mycmdz} {
\mycmdb{}
\mycmdx{}
\typeout{mycmdz}
}
}{}
\NewDocumentCommand{mycmdx} {
\typeout{mycmdx}
}
}{}
\NewDocumentCommand{mycmdb} {
\typeout{mycmdb}
}
}{}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenvb}
\end{document}
但是我在尝试编译时收到此错误:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "xparse/command-already-defined"
!
! Command 'mycmda' already defined!
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l.51 \begin
{myenvx}
我不确定如何准确定义嵌套环境。它曾经在 LaTeX2 中工作\newenvironment
,但似乎在 LaTeX3 中不起作用。不确定可能出了什么问题,似乎可能有几件事。目标是能够定义嵌套环境和命令,其中不同环境中的子命令中的名称相同。
(我希望环境的范围像这样,这样就可以用不同的方式处理它们。)
我认为我不应该\DeclareDocumentCommand
在任何地方使用。也许我应该在这里使用新的 LaTeX3 函数,但不确定。我可以通过使用 来获得更进一步的结果\cs_new:Npn
,如在这个 MWE 中:
\documentclass[a4paper]{article}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\begin{document}
\NewDocumentEnvironment{myenva}{} {
\NewDocumentEnvironment{myenvx}{} {
\NewDocumentEnvironment{myenvz}{} {
\cs_new:Npn \mycmdz {
\mycmda{}
\mycmdx{}
\typeout{mycmdz}
}
}{}
\cs_new:Npn \mycmdx {
\typeout{mycmdx}
}
}{}
\cs_new:Npn \mycmda {
\typeout{mycmda}
}
}{}
\NewDocumentEnvironment{myenvb}{} {
\NewDocumentEnvironment{myenvx}{} {
\NewDocumentEnvironment{myenvz}{} {
\cs_new:Npn \mycmdz {
\mycmda{}
\mycmdx{}
\typeout{mycmdz}
}
}{}
\cs_new:Npn \mycmdx {
\typeout{mycmdx}
}
}{}
\cs_new:Npn \mycmdb {
\typeout{mycmdb}
}
}{}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenvb}
\end{document}
但仍然出错:
mycmda
mycmdx
mycmdz
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/command-already-defined"
!
! Control sequence \mycmdx already defined.
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
使用 LaTeX2 功能时,我能够实现所需的行为,如以下 MWE 所示:
\documentclass[a4paper]{article}
\usepackage{expl3}
\usepackage{xparse}
\begin{document}
\newenvironment{myenva} {
\newenvironment{myenvx} {
\newenvironment{myenvz} {
\newcommand{\mycmdz} {
\mycmda{}
\mycmdx{}
\typeout{mycmdz}
}
}{}
\newcommand{\mycmdx} {
\typeout{mycmdx}
}
}{}
\newcommand{\mycmda} {
\typeout{mycmda}
}
}{}
\newenvironment{myenvb} {
\newenvironment{myenvx} {
\newenvironment{myenvz} {
\newcommand{\mycmdz} {
\mycmdb{}
\mycmdx{}
\typeout{mycmdz}
}
}{}
\newcommand{\mycmdx} {
\typeout{mycmdx}
}
}{}
\newcommand{\mycmdb} {
\typeout{mycmdb}
}
}{}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenvb}
\end{document}
但是,我想在完成嵌套环境/命令时利用以下功能:
- 使用 LaTeX3 功能。
- 得益于 ,可以进行动态/重载参数解析
xparse
。
更新
我尝试了更多的排列以确保它涵盖了我所寻找的情况,并且一切似乎都有效,耶!
\documentclass[a4paper]{article}
\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{myenvx}{}{}{}
\NewDocumentEnvironment{myenvz}{}{}{}
\NewDocumentCommand{\mycmdz}{}{}
\NewDocumentEnvironment{myenva}{}{%
\NewDocumentCommand{\mycmda}{mm}{%
\typeout{mycmda}
\typeout{##1}
\typeout{##2}
}%
\RenewDocumentEnvironment{myenvx}{}{%
\NewDocumentCommand{\mycmdx}{mm}{%
\typeout{mycmdx}
\typeout{####1}
\typeout{####2}
}%
\RenewDocumentEnvironment{myenvz}{}{%
\RenewDocumentCommand{\mycmdz}{mm}{%
\mycmda{mycmda:a}{mycmda:b}
\mycmdx{mycmda:mycmdx:a}{mycmda:mycmdx:b}
\typeout{mycmdz}
\typeout{########1}
\typeout{########2}
}%
}{}%
%
}{}%
%
}{}
\NewDocumentEnvironment{myenvb}{} {%
\NewDocumentCommand{\mycmdb}{}{%
\typeout{mycmdb}
}%
\RenewDocumentEnvironment{myenvx}{} {%
\NewDocumentCommand{\mycmdx}{mmm}{%
\typeout{mycmdx}
\typeout{####1}
\typeout{####2}
\typeout{####3}
}%
\RenewDocumentEnvironment{myenvz}{} {%
\RenewDocumentCommand{\mycmdz}{mmm}{%
\mycmdb{}
\mycmdx{mycmdb:mycmdx:a}{mycmdb:mycmdx:b}{mycmdb:mycmdx:c}
\typeout{mycmdz}
\typeout{########1}
\typeout{########2}
\typeout{########3}
}%
}{}%
%
}{}%
%
}{}
\begin{document}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{mycmda:mycmdx:mycmdz:a}{mycmda:mycmdx:mycmdz:b}
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz{mycmdb:mycmdx:mycmdz:a}{mycmdb:mycmdx:mycmdz:b}{mycmdb:mycmdx:mycmdz:c}
\end{myenvz}
\end{myenvx}
\end{myenvb}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{mycmda:mycmdx:mycmdz:a}{mycmda:mycmdx:mycmdz:b}
\end{myenvz}
\end{myenvx}
\end{myenva}
\end{document}
输出:
mycmda
mycmda:a
mycmda:b
mycmdx
mycmda:mycmdx:a
mycmda:mycmdx:b
mycmdz
mycmda:mycmdx:mycmdz:a
mycmda:mycmdx:mycmdz:b
mycmdb
mycmdx
mycmdb:mycmdx:a
mycmdb:mycmdx:b
mycmdb:mycmdx:c
mycmdz
mycmdb:mycmdx:mycmdz:a
mycmdb:mycmdx:mycmdz:b
mycmdb:mycmdx:mycmdz:c
mycmda
mycmda:a
mycmda:b
mycmdx
mycmda:mycmdx:a
mycmda:mycmdx:b
mycmdz
mycmda:mycmdx:mycmdz:a
mycmda:mycmdx:mycmdz:b
更新 2
似乎没有RenewDocumentCommand
和也可以工作RenewDocumentEnvironment
。
\documentclass[a4paper]{article}
\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{myenva}{}{
\NewDocumentCommand{\mycmda}{mm}{
\typeout{mycmda}
\typeout{##1}
\typeout{##2}
}
\NewDocumentEnvironment{myenvx}{}{
\NewDocumentCommand{\mycmdx}{mm}{
\typeout{mycmdx}
\typeout{####1}
\typeout{####2}
}
\NewDocumentEnvironment{myenvz}{}{
\NewDocumentCommand{\mycmdz}{mm}{
\mycmda{mycmda:a}{mycmda:b}
\mycmdx{mycmda:mycmdx:a}{mycmda:mycmdx:b}
\typeout{mycmdz}
\typeout{########1}
\typeout{########2}
}
}{}
}{}
}{}
\NewDocumentEnvironment{myenvb}{} {
\NewDocumentCommand{\mycmdb}{}{
\typeout{mycmdb}
}
\NewDocumentEnvironment{myenvx}{} {
\NewDocumentCommand{\mycmdx}{mmm}{
\typeout{mycmdx}
\typeout{####1}
\typeout{####2}
\typeout{####3}
}
\NewDocumentEnvironment{myenvz}{} {
\NewDocumentCommand{\mycmdz}{mmm}{
\mycmdb{}
\mycmdx{mycmdb:mycmdx:a}{mycmdb:mycmdx:b}{mycmdb:mycmdx:c}
\typeout{mycmdz}
\typeout{########1}
\typeout{########2}
\typeout{########3}
}
}{}
}{}
}{}
\begin{document}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{mycmda:mycmdx:mycmdz:a}{mycmda:mycmdx:mycmdz:b}
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz{mycmdb:mycmdx:mycmdz:a}{mycmdb:mycmdx:mycmdz:b}{mycmdb:mycmdx:mycmdz:c}
\end{myenvz}
\end{myenvx}
\end{myenvb}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{mycmda:mycmdx:mycmdz:a}{mycmda:mycmdx:mycmdz:b}
\end{myenvz}
\end{myenvx}
\end{myenva}
\end{document}
答案1
我认为这就是你所需要的:
##笔记:
首先定义每个环境/宏,然后根据需要重新定义它们。在这种情况下,定义似乎只是本地的,因此您不一定需要先定义它们然后重新定义它们。我倾向于始终先定义它们然后重新定义它们,以确保不会在其他地方使用相同的名称。更新定义只是检查名称是否已定义,它不会检查参数规范是否匹配,因此您可以根据需要自由地在本地更改它们。
宏名称以斜杠开头
\
,环境名称则不然。\NewDocumentEnvironment
/\RenewDocumentCommand
需要参数规范,因此如果没有参数(如这里的情况),您必须指定一个空的参数规范{}
。您的 MWE 中缺少这些。因此,一般格式是\NewDocumentCommand{<macro name starting with a slash>}{<arg spec>}{<body>}
类似地,
\NewDocumentEnvironment
/\RenewDocumentEnvironment
也需要参数规范。您的 MWE 中缺少这些。因此,一般格式为\NewDocumentEnvironment{<env name without leading slash>}{<arg spec>}{<begin env code>}{<end env code>}
当你想要一个宏时仅有的被定义为之内另一个环境/宏,你应该定义它前使用它。因此,我将这些定义上移。
另外,要小心虚假的空格。请参阅此Tex 容量超出范围(如果在使用宏后删除%)作为如果不这样做会发生什么情况的一个例子。
由于我不能 100% 确定哪些地方不需要,我往往会添加比实际需要更多的内容。然而,我因过度使用而受到责备在 \newcommand 或类似命令中,在行尾添加百分号什么时候有害。不过,我也自动添加\relax
以下任何类型\nuxper
,\dimexpr
所以没有然而遇到过度使用造成的任何问题(但我不推荐这样做)。
当遇到问题时,我的建议是,在尝试更复杂的事情之前,先让初始版本尽可能简单。例如,你可以先从单身的(非嵌套)宏定义,以确保正确无误。这会显示缺少参数规范和宏名称的问题。然后单身的(非嵌套)环境,以确保正确无误。然后从那里构建嵌套环境(只需从两个级别开始,没有必要从三个级别开始)。
如果嵌套的宏/环境有参数,要访问它们,您需要双重使用
#
。有关更多信息,请参阅:据我所知,使用
\ExplSyntaxOn
可以省略%
,但宏中的文本中的任何空格也将被删除。您可以自行决定如何处理空格:在定义中,或在文本中。
##代码:
\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}
\NewDocumentEnvironment{myenvx}{}{}{}
\NewDocumentEnvironment{myenvz}{}{}{}
\NewDocumentCommand{\mycmdz}{}{}
\NewDocumentEnvironment{myenva}{}{%
\NewDocumentCommand{\mycmda}{}{%
\typeout{mycmda}
}%
\RenewDocumentEnvironment{myenvx}{}{%
\NewDocumentCommand{\mycmdx}{}{%
\typeout{mycmdx}
}%
\RenewDocumentEnvironment{myenvz}{}{%
\RenewDocumentCommand{\mycmdz}{}{%
\mycmda{}
\mycmdx{}
\typeout{mycmdz}
}%
}{}%
%
}{}%
%
}{}
\NewDocumentEnvironment{myenvb}{} {%
\NewDocumentCommand{\mycmdb}{}{%
\typeout{mycmdb}
}%
\RenewDocumentEnvironment{myenvx}{} {%
\NewDocumentCommand{\mycmdx}{}{%
\typeout{mycmdx}
}%
\RenewDocumentEnvironment{myenvz}{} {%
\RenewDocumentCommand{\mycmdz}{}{%
\mycmdb{}
\mycmdx{}
\typeout{mycmdz}
}%
}{}%
%
}{}%
%
}{}
\begin{document}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz{}
\end{myenvz}
\end{myenvx}
\end{myenvb}
\end{document}
答案2
让内部命令适应其上下文通常比让外部命令重新定义一切更简单。
这里我只是输入,制作
myenva:myenvx:myenvz:mycmdz
myenvb:myenvx:myenvz:mycmdz
但给定这些不同的序列,\mycmdz
可以执行任意不同的代码。
\documentclass[a4paper]{article}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\makeatletter
\cs_new:Nn\colonify:n{#1:}
\seq_new:N\zz_seq{}
\NewDocumentEnvironment{myenva}{}{\seq_put_right:Nx\zz_seq{\@currenvir}} {}
\NewDocumentEnvironment{myenvb}{}{\seq_put_right:Nx\zz_seq{\@currenvir}} {}
\NewDocumentEnvironment{myenvx}{}{\seq_put_right:Nx\zz_seq{\@currenvir}} {}
\NewDocumentEnvironment{myenvz}{}{\seq_put_right:Nx\zz_seq{\@currenvir}} {}
\NewDocumentCommand\mycmdz{}{
\typeout{
\seq_map_function:NN\zz_seq\colonify:n mycmdz
}}
\ExplSyntaxOff
\begin{document}
\begin{myenva}
\begin{myenvx}
\begin{myenvz}
\mycmdz
\end{myenvz}
\end{myenvx}
\end{myenva}
\begin{myenvb}
\begin{myenvx}
\begin{myenvz}
\mycmdz
\end{myenvz}
\end{myenvx}
\end{myenvb}
\end{document}