如何创建管道分割元组?

如何创建管道分割元组?

我正在尝试编写一个宏,\tup它可以有效地扩展它:

\tup{a | b | ... | z}

更改为:

\left\langle a ~\middle|~ b ~\middle|~ ... ~\middle|~ z \right\rangle

我尝试了以下操作,但它只放下第一个分隔符然后停止。

\documentclass[preview]{standalone}

\newcommand{\brak}[1]{\ensuremath{\left\langle#1\right\rangle}}

\makeatletter
\newcommand{\tup}[1]{%
    \begingroup%
    \@tempswafalse%
    \def\@sep{~\middle|~}%
    \edef\@tempa{#1|}%
    \expandafter\brak\expandafter{\expandafter\@tuploop\@tempa\relax}%
    \endgroup%
}
\def\@tuploop#1|#2\relax{%
      \if@tempswa\@sep\else\@tempswatrue\fi{#1}
      \begingroup
      \ifx\relax#2\relax
         \renewcommand{\next}{\endgroup}%
      \else
         \renewcommand{\next}{\endgroup\@tuploop#2\relax}%
      \fi
      \next
}
\makeatother

\begin{document}
$\tup{a|b|c}$
\end{document}

输出错误 — — 只有一个管道字符

但是,如果我将定义更改\@sep为,\def\@sep{~|~}那么它就会“起作用”,并将管道字符放在

输出正常——两个都是管道字符,但没有高度调整

我认为\middle扩展可能为时过早,但我不知道该怎么做。我该如何实现它?

答案1

我认为你不需要循环:

在此处输入图片描述

\documentclass{article}

\begingroup
\lccode`\~=`\|
\lowercase{\endgroup
\def\tup#1{{\def~{\;\middle\vert\;}\mathcode`\|="8000\left\langle#1\right\rangle}}}

\begin{document}

\[
\tup{a | b | c | z} + \tup{a |\frac{A}{B} | c | z}
\]

\end{document}

答案2

作为一般规则,我建议尽可能\left避免。\right

\DeclarePairedDelimiter下面是一个与使用from定义的命令具有类似语法的实现mathtools

未修饰的命令使用正常大小;在可选参数中可以出现\big\Big或。表示使用自动调整大小。\bigg\Bigg*

强制参数中的空格将被忽略,因此\tup{a|b|c}与 相同\tup{a | b | c}

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\tup}{som}
 {
  \IfBooleanTF{#1}
   {
    \tl_set:Nn \l__reinking_tup_open_tl { \left\langle }
    \tl_set:Nn \l__reinking_tup_middle_tl { \;\middle|\; }
    \tl_set:Nn \l__reinking_tup_close_tl { \right\rangle }
   }
   {
    \IfNoValueTF{#2}
     {
      \tl_set:Nn \l__reinking_tup_open_tl { \langle }
      \tl_set:Nn \l__reinking_tup_middle_tl { \mathrel{|} }
      \tl_set:Nn \l__reinking_tup_close_tl { \rangle }
     }
     {
      \tl_set:Nn \l__reinking_tup_open_tl { \mathopen{#2\langle} }
      \tl_set:Nn \l__reinking_tup_middle_tl { \mathrel{#2|} }
      \tl_set:Nn \l__reinking_tup_close_tl { \mathclose{#2\rangle} }
     }
   }
  \__reinking_tup:n { #3 }
 }

\tl_new:N \l__reinking_tup_open_tl
\tl_new:N \l__reinking_tup_middle_tl
\tl_new:N \l__reinking_tup_close_tl
\seq_new:N \l__reinking_tup_items_seq

\cs_new_protected:Nn \__reinking_tup:n
 {
  \seq_set_split:Nnn \l__reinking_tup_items_seq { | } { #1 }
  \l__reinking_tup_open_tl
  \seq_use:NV \l__reinking_tup_items_seq \l__reinking_tup_middle_tl
  \l__reinking_tup_close_tl
 }
\cs_generate_variant:Nn \seq_use:Nn { NV }

\ExplSyntaxOff

\begin{document}

$\tup{a|b|\dots|z}$
\quad
$\tup[\big]{a|b|\dots|z}$
\quad
$\tup[\Big]{a|b|\dots|z}$
\quad
$\tup*{\dfrac{a}{2}|b|\dots|z}$

\end{document}

在此处输入图片描述

无软件包版本,它不加区别地使用\left\middle\right。每次吸收一项并附加到列表中,然后执行该列表。

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand{\tup}[1]{%
  \def\@tup@list{}%
  \@tup#1|\@tup|
}
\def\@tup#1|{%
  \ifx\@tup#1\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\left\langle\@tup@list\right\rangle}%
  {\ifx\@tup@list\@empty\@tup@append{#1}\else\@tup@append{\;\middle|\;#1}\fi\@tup}%
}
\def\@tup@append#1{%
  \expandafter\def\expandafter\@tup@list\expandafter{\@tup@list#1}%
}
\makeatother

\begin{document}

$\tup{a}$

$\tup{a|b|\dots|z}$

\end{document}

这样,由\left\middle和隐式形成的组就不会出现问题\right

答案3

你的命令是几乎正在工作。如果您将更多项目放入其中\tup,则会$\tup{a|b|c|d|e|f}$看到以下内容:

在此处输入图片描述

第一个项不是被遗漏的,而是成对分组的。您的命令以 开头\left\langle,它启动一个“数学左组”,并将\@tempswa开关设置为 false。在 的第一次迭代中,\@tuploop您将执行\if@tempswa\@sep\else\@tempswatrue\fi扩展为\@tempswatrue,这意味着\@sep现在没有插入,并且\@tempswa现在为真。然后,该命令插入第一个项(a)并继续进行下一次迭代。

在第二次迭代中,\@tempswa为真并\if@tempswa\@sep\else\@tempswatrue\fi扩展为\@sep,插入\middle|(后面的分隔符a)。\middle基元将结束由 开始的“数学左组” \left\langle,并将开始另一个“数学左组”。但是,当第一个组结束时,您的\@tempswa开关恢复为当前组之外的值,即 false!现在命令插入b并转到第三次迭代,但现在\@tempswa再次设置为 false。

因此,由于触发了组的结束,因此您的命令实际上是插入,<token>|<token>然后等等。您可以使用一些魔法来规避这个问题,或者简单地对开关进行全局分配:<token>|<token>\middle\aftergroup

\if@tempswa\@sep\else\global\@tempswatrue\fi

但是,正如 egreg 在评论中所说,\@tempswa应该仅在本地设置,因此最好创建一个\newif\ifg@insertsep然后始终使用\global\g@insertseptrue\global\g@insertsepfalse

与此同时,由于 egreg 发布的expl3答案比我发布的单行答案更为详细,因此我将在这里停止;-)

答案4

似乎还有空间再回答一个问题,其中可以提到所有这些似乎都是很久以前完成的。

\documentclass{article}
\usepackage{braket}
\begin{document}
\[
\Braket{a | b | c | z} + \Braket{a |\frac{A}{B} | c | z}
\]
\end{document}

在此处输入图片描述

那时他们也不需要循环。;-)

相关内容