原始答案

原始答案

我的 MWE 使用 LuaLaTeX:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack}
\usepackage[automark]{scrlayer-scrpage}
\usepackage[english]{babel}
\usepackage[babel]{microtype}
\usepackage{mathtools, amssymb}
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts
    \setmathfont{Latin Modern Math}
\usepackage{setspace}\setdisplayskipstretch{}
\usepackage{enumitem}
\usepackage{xparse}
\usepackage{environ}
\usepackage{keyval}
\usepackage{lipsum}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \adjintertext custom spacing \intertext macro (https://tex.stackexchange.com/a/280847/228055)
    \MHInternalSyntaxOn
    \newcommand{\adjintertext}[3]% #1=above skip, #2=below skip, #3=text
    {\ifvmode\else\\\@empty\fi
      \noalign{%
        %\penalty\postdisplaypenalty\vskip\belowdisplayskip
        \vskip-\lineskiplimit      % CCS
        \vskip\normallineskiplimit % CCS
        \vskip#1
        \vbox{\normalbaselines
            \ifdim
            \ifdim\@totalleftmargin=\z@
                \linewidth
            \else
                -\maxdimen
            \fi
            =\columnwidth
            \else \parshape\@ne \@totalleftmargin \linewidth
            \fi
        \noindent#3\par}%
        %\penalty\predisplaypenalty\vskip\abovedisplayskip%
        \vskip-\lineskiplimit      % CCS
        \vskip\normallineskiplimit % CCS
        \vskip#2
    }}%
    \MHInternalSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6]
\begin{flalign*}
& \text{For any numbers \(a\)}
&& \tag{P'10} \\
%%%%% the part related to the question %%%%%
\adjintertext{0pt}{12pt}{\centering%
  $\begin{alignedat}{2}
     & \text{(i) }   & a &= b, \\
     & \text{(ii) }  & a &< b, \\
     & \text{(iii) } & b &< a.
  \end{alignedat}$%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) and \(b < c\), then \(a < c\).}
&& \tag{P'11} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\), then \(a + c < b + c\).}
&& \tag{P'12} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) abd \(0 < c\), then \(ac < bc\).}
&& \tag{P'13}
\end{flalign*}
\lipsum[2][1-8]

\end{document}

在此处输入图片描述

我想创建一个新的环境myalignedat来排版居中和对齐的方程式,就像我的 MWE 一样,这样就不用再输入

\begin{<display math mode environment>}
    \adjintertext{0pt}{12pt}{\centering%
     \(\begin{alignedat}{2}
     & \text{(i) }   & a &= b, \\
     & \text{(ii) }  & a &< b, \\
     & \text{(iii) } & b &< a.
    \end{alignedat}\)%
}
\end{<display math mode environment>}

我会输入以下内容:

\begin{<display math mode environment>}
    \begin{myalignedat}{2}[before skip=0pt, after skip=12pt]
        & \text{(i) }   & a &= b, \\
        & \text{(ii) }  & a &< b, \\
        & \text{(iii) } & b &< a.
    \end{myalignedat}
\end{<display math mode environment>}

类似于tcolorbox为其环境做这件事。

我的问题是:我该如何定义这样的环境?

我尝试过使用\newenvironenvironxparse包,但由于我对此事了解甚少,因此无济于事。谢谢。

答案1

原始答案

为了使其工作,我们必须以某种方式将\noalign置于 TeX 可以找到它的位置(在定义内部\begin{myalignedat}这样做似乎太晚了)。因此,下面使用env/myalignedat/beforeenv/myalignedat/after钩子以及一些括号技巧(\ifnum0=`{\ifnum0=`})将 置于\noalign我们需要的位置。此外,我们需要\adjintertext在我们的环境中重新实现代码。

一旦我们解决了这个问题,剩下的就很简单了,我们只需收集一个可选参数和一个强制参数,并使用任何key=val符合我们需求的实现(以下使用expkvexpkv-def定义前端1,但其他包也可以使用)。另一个小调整(虽然这不是必需的)是以下内容不使用\begin{alignedat}...\end{alignedat}but \alignedat...\endalignedat

完整代码:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack}
\usepackage[automark]{scrlayer-scrpage}
\usepackage[english]{babel}
\usepackage[babel]{microtype}
\usepackage{mathtools, amssymb}
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts
    \setmathfont{Latin Modern Math}
\usepackage{setspace}\setdisplayskipstretch{}
\usepackage{enumitem}
\usepackage{xparse}
\usepackage{environ}
\usepackage{lipsum}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \adjintertext custom spacing \intertext macro (https://tex.stackexchange.com/a/280847/228055)
    \MHInternalSyntaxOn
    \newcommand{\adjintertext}[3]% #1=above skip, #2=below skip, #3=text
    {\ifvmode\else\\\@empty\fi
      \noalign{%
        %\penalty\postdisplaypenalty\vskip\belowdisplayskip
        \vskip-\lineskiplimit      % CCS
        \vskip\normallineskiplimit % CCS
        \vskip#1
        \vbox{\normalbaselines
            \ifdim
            \ifdim\@totalleftmargin=\z@
                \linewidth
            \else
                -\maxdimen
            \fi
            =\columnwidth
            \else \parshape\@ne \@totalleftmargin \linewidth
            \fi
        \noindent#3\par}%
        %\penalty\predisplaypenalty\vskip\abovedisplayskip%
        \vskip-\lineskiplimit      % CCS
        \vskip\normallineskiplimit % CCS
        \vskip#2
    }}%
    \MHInternalSyntaxOff
\makeatletter
\usepackage{expkv-def}
\ekvdefinekeys{myalignedat}
  {
     skip before skip = \myalignedat@before
    ,skip after skip  = \myalignedat@after
  }
\AddToHook{env/myalignedat/before}
  {\ifvmode\else\\\@empty\fi\noalign{\ifnum0=`}\fi}
\AddToHook{env/myalignedat/after}
  {\ifnum0=`{\fi}}
\MHInternalSyntaxOn
\newenvironment{myalignedat}[2][]
  {%
    \ekvset{myalignedat}{#1}%
    \vskip\myalignedat@before
    \vbox\bgroup\normalbaselines
      \ifdim
        \ifdim\@totalleftmargin=\z@
          \linewidth
        \else
          -\maxdimen
        \fi
        =\columnwidth
      \else
        \parshap\@ne\@totalleftmargin \linewidth
      \fi
      \noindent
      \centering\(\alignedat{#2}%
  }
  {%
      \endalignedat\)%
    \par\egroup
    \vskip-\lineskiplimit
    \vskip\normallineskiplimit
    \vskip\myalignedat@after
  }
\MHInternalSyntaxOff
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6]
\begin{flalign*}
& \text{For any numbers \(a\)}
&& \tag{P'10} \\
%%%%% the part related to the question %%%%%
\begin{myalignedat}[before skip=0pt, after skip=12pt]{2}
   & \text{(i) }   & a &= b, \\
   & \text{(ii) }  & a &< b, \\
   & \text{(iii) } & b &< a.
\end{myalignedat}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) and \(b < c\), then \(a < c\).}
&& \tag{P'11} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\), then \(a + c < b + c\).}
&& \tag{P'12} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) abd \(0 < c\), then \(ac < bc\).}
&& \tag{P'13}
\end{flalign*}
\lipsum[2][1-8]

\end{document}

输出:

在此处输入图片描述

1免责声明:我是软件包的作者expkv和朋友


改进版本需要破解\begin

上述代码版本无法检测 a\\之前是否使用过,因此导致垂直间距不一致。以下代码通过修补 LaTeX\begin以添加另一个钩子来修复此问题。修补程序应该没问题,并且不会影响 的任何其他使用\begin

\documentclass[oneside,DIV=12]{scrbook}

\makeatletter
% redefine `\begin` to have another hook. This hook is no generic hook, so we
% have to use `\NewHook{env/#1/evenbeforebefore}` before we can use `\AddToHook`
% on it (for each environment that needs it)
\edef\begin#1%
  {%
    \unexpanded
      {%
        \ifx\protect\relax
        \else
          \expandafter\@gobbletwo
        \fi
      }%
    \noexpand\UseHook{env/#1/evenbeforebefore}%
    \noexpand\protect\expandafter\noexpand\csname begin \endcsname{#1}%
  }
\makeatother

\usepackage{scrhack}
\usepackage[automark]{scrlayer-scrpage}
\usepackage[english]{babel}
\usepackage[babel]{microtype}
\usepackage{mathtools, amssymb}
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts
    \setmathfont{Latin Modern Math}
\usepackage{setspace}\setdisplayskipstretch{}
\usepackage{lipsum}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\makeatletter
\usepackage{expkv-def}
\ekvdefinekeys{myalignedat}
  {
     skip before skip = \myalignedat@before
    ,skip after skip  = \myalignedat@after
  }
\NewHook{env/myalignedat/evenbeforebefore}
\AddToHook{env/myalignedat/evenbeforebefore}
  {\ifvmode\else\\\@empty\fi\noalign{\ifnum0=`}\fi}
\AddToHook{env/myalignedat/after}
  {\ifnum0=`{\fi}}
\MHInternalSyntaxOn
\newenvironment{myalignedat}[2][]
  {%
    \ekvset{myalignedat}{#1}%
    \vskip\myalignedat@before
    \vbox\bgroup\normalbaselines
      \ifdim
        \ifdim\@totalleftmargin=\z@
          \linewidth
        \else
          -\maxdimen
        \fi
        =\columnwidth
      \else
        \parshap\@ne\@totalleftmargin \linewidth
      \fi
      \noindent
      \centering\(\alignedat{#2}%
  }
  {%
      \endalignedat\)%
    \par\egroup
    \vskip-\lineskiplimit
    \vskip\normallineskiplimit
    \vskip\myalignedat@after
  }
\MHInternalSyntaxOff
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
\onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6]
\begin{flalign*}
& \text{For any numbers \(a\) with much text following it}
&& \tag{P'10} \\
%%%%% the part related to the question %%%%%
\begin{myalignedat}[before skip=0pt, after skip=0pt]{2}
   & \text{(i) }   & a &= b, \\
   & \text{(ii) }  & a &< b, \\
   & \text{(iii) } & b &< a.
\end{myalignedat}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) and \(b < c\), then \(a < c\).}
&& \tag{P'11} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\), then \(a + c < b + c\).}
&& \tag{P'12} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) abd \(0 < c\), then \(ac < bc\).}
&& \tag{P'13}
\end{flalign*}
\lipsum[2][1-8]

\end{document}

伪环境版本

此版本使用完全可扩展的宏来启动伪环境。它不需要对标准 LaTeX 宏进行任何黑客攻击,但它仍然使用括号黑客攻击。它\noalign直接扩展到,然后可以使用不可扩展的参数抓取和 key=value 解析。

环境由 开始\beginmyalignedat[<key=value>]{<alignedat-arg>},并由 结束\stopmyalignedat

完整代码:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack}
\usepackage[automark]{scrlayer-scrpage}
\usepackage[english]{babel}
\usepackage[babel]{microtype}
\usepackage{mathtools, amssymb}
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts
    \setmathfont{Latin Modern Math}
\usepackage{setspace}\setdisplayskipstretch{}
\usepackage{enumitem}
\usepackage{xparse}
\usepackage{environ}
\usepackage{keyval}
\usepackage{lipsum}

\usepackage{expkv-def}

\makeatletter
\ekvdefinekeys{myalignedat}
  {
     skip before skip = \myalignedat@before
    ,skip after skip  = \myalignedat@after
  }
\MHInternalSyntaxOn
\newcommand*\beginmyalignedat
  {%
    \ifvmode\else\\\@empty\fi
    \noalign{\ifnum0=`}\fi
      \myalignedat@
  }
\newcommand\myalignedat@[2][]
  {%
      \ekvset{myalignedat}{#1}%
      \vskip-\lineskiplimit
      \vskip\normallineskiplimit
      \vskip\myalignedat@before
      \vbox\bgroup
        \normalbaselines
        \ifdim
          \ifdim\@totalleftmargin=\z@
            \linewidth
          \else
            -\maxdimen
          \fi
          =\columnwidth
        \else
          \parshape\@ne\@totalleftmargin\linewidth
        \fi
        \noindent
        \centering
        $\begin{alignedat}{#2}%
  }
\newcommand\stopmyalignedat
  {%
        \end{alignedat}$%
        \par
        \vskip-\lineskiplimit
        \vskip\normallineskiplimit
        \vskip\myalignedat@after
      \egroup
    \ifnum0=`{\fi}%
  }
\MHInternalSyntaxOff
\makeatother

\begin{document}
\onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6]
\begin{flalign*}
& \text{For any numbers \(a\)}
&& \tag{P'10} \\
%%%%% the part related to the question %%%%%
\beginmyalignedat[after skip=12pt]{2}
   & \text{(i) }   & a &= b, \\
   & \text{(ii) }  & a &< b, \\
   & \text{(iii) } & b &< a.
\stopmyalignedat
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) and \(b < c\), then \(a < c\).}
&& \tag{P'11} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\), then \(a + c < b + c\).}
&& \tag{P'12} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) abd \(0 < c\), then \(ac < bc\).}
&& \tag{P'13}
\end{flalign*}
\lipsum[2][1-8]

\end{document}

普通宏版本

一种宏变体,它以可扩展的方式抓取参数,使用可扩展的 key=value 接口,因此“直接”扩展为\adjintertext,这样它的行为就像\adjintertext在您的代码中使用一样。替代版本可以使用与其他解决方案相同的括号技巧来使用不可扩展的参数抓取和 key=value 解决方案。

语法是:

\myalignedat[<key=val>]{<alignedat-arg>}{<alignedat-content>}

完整代码:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack}
\usepackage[automark]{scrlayer-scrpage}
\usepackage[english]{babel}
\usepackage[babel]{microtype}
\usepackage{mathtools, amssymb}
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts
    \setmathfont{Latin Modern Math}
\usepackage{setspace}\setdisplayskipstretch{}
\usepackage{enumitem}
\usepackage{xparse}
\usepackage{environ}
\usepackage{keyval}
\usepackage{lipsum}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \adjintertext custom spacing \intertext macro (https://tex.stackexchange.com/a/280847/228055)
    \MHInternalSyntaxOn
    \newcommand{\adjintertext}[3]% #1=above skip, #2=below skip, #3=text
    {\ifvmode\else\\\@empty\fi
      \noalign{%
        %\penalty\postdisplaypenalty\vskip\belowdisplayskip
        \vskip-\lineskiplimit      % CCS
        \vskip\normallineskiplimit % CCS
        \vskip#1
        \vbox{\normalbaselines
            \ifdim
            \ifdim\@totalleftmargin=\z@
                \linewidth
            \else
                -\maxdimen
            \fi
            =\columnwidth
            \else \parshape\@ne \@totalleftmargin \linewidth
            \fi
        \noindent#3\par}%
        %\penalty\predisplaypenalty\vskip\abovedisplayskip%
        \vskip-\lineskiplimit      % CCS
        \vskip\normallineskiplimit % CCS
        \vskip#2
    }}%
    \MHInternalSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\usepackage{expkv-cs}

% grabbing an optional argument expandable
\NewExpandableDocumentCommand\myalignedat{O{} m m}
  {%
    % forward all arguments to \myalignedatKV
    \myalignedatKV{#1}{#2}{#3}%
  }
% splitting the first argument into two arguments based on a key=value interface
\ekvcSplitAndForward\myalignedatKV\myalignedatDO
  {
     before skip=0pt
    ,after  skip=0pt
  }
% grabbing all the arguments and setting the output
\newcommand\myalignedatDO[4]
  {%
    \adjintertext{#1}{#2}
      {%
        \centering
        $%
        \begin{alignedat}{#3}
          #4%
        \end{alignedat}%
        $%
      }%
  }

\begin{document}
\onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6]
\begin{flalign*}
& \text{For any numbers \(a\)}
&& \tag{P'10} \\
%%%%% the part related to the question %%%%%
\myalignedat[after skip=12pt]{2}
  {
     & \text{(i) }   & a &= b, \\
     & \text{(ii) }  & a &< b, \\
     & \text{(iii) } & b &< a.
  }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) and \(b < c\), then \(a < c\).}
&& \tag{P'11} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\), then \(a + c < b + c\).}
&& \tag{P'12} \\
& \text{For any numbers \(a\), \(b\), and \(c\), if \(a < b\) abd \(0 < c\), then \(ac < bc\).}
&& \tag{P'13}
\end{flalign*}
\lipsum[2][1-8]

\end{document}

相关内容