向我解释此代码:双重分隔符

向我解释此代码:双重分隔符

不久前我问过这个问题双重分隔符。我发现这段代码并将其改编为以下内容:

\documentclass{article}

\usepackage{mathtools}

\DeclarePairedDelimiterX{\dbrackets}[1]{\lbrack}{\rbrack}{
    \nhphantom{$\delimsize\lbrack$} \delimsize\lbrack \mathopen{} #1 \mathclose{} \delimsize\rbrack \nhphantom{$\delimsize\rbrack$}
}
\DeclarePairedDelimiterX{\dbraces}[1]{\lbrace}{\rbrace}{
    \nhphantom{$\delimsize\lbrace$} \delimsize\lbrace \mathopen{} #1 \mathclose{} \delimsize\rbrace \nhphantom{$\delimsize\rbrace$}
}
\DeclarePairedDelimiterX{\dparens}[1]{\lparen}{\rparen}{
    \nhphantom{$\delimsize\lparen$} \delimsize\lparen \mathopen{} #1 \mathclose{} \delimsize\rparen \nhphantom{$\delimsize\rparen$}
}


\newcommand{\nhphantom}[1]{\sbox0{#1}\hspace{-0.751\dimexpr\the\wd0 \relax}}


\begin{document}

$\dbrackets[\big]{\frac12}$
$\dbraces[\big]{\frac12}$
$\dparens[\big]{\frac12}$

%These don't work:

%$\dbrackets*{\frac12}$
%$\dbraces*{\frac12}$
%$\dparens*{\frac12}$

\end{document}

它确实实现了我想要的功能,但我不太理解代码,而且有很多我从未见过的宏。所以如果有人能向我解释一下这里发生了什么,我将不胜感激:

  • 宏的意图是什么\nhphantom
  • 做什么\sbox0
  • 做什么\dimexpr\the\wd0

我还想了解为什么带星号版本的命令mathtools不起作用。

答案1

TeX 有一个东西叫盒子,这是它用来组织文档中内容的东西。Knuth 的 TeX 有 256 个盒子寄存器供您使用。可以将其视为 TeX 可用的 256 个实际盒子,用于存储内容,然后在文档中使用它们。

该命令\sbox0{#1}将的内容放入#1盒子寄存器 n° 中0

现在盒子寄存器0已经有了,#1您可以对这个盒子做一些事情,比如用 测量它的宽度\wd、用 测量高度\ht、用 测量深度\dp,所以\wd0返回盒子内容的0

因此,分解一下\nhphantom宏:

% Store the contents of #1 into box register 0
\sbox0{#1}%
% Go back -0.751 times the \wd of the box register 0
\hspace{-0.751\dimexpr\the\wd0 \relax}

此外,正如 egreg 在评论中所说,-0.751\dimexpr\the\wd0是多余的。\the将获取 的文本表示\wd0,然后\dimexpr将此文本读回数字。您可以使用 跳过这种来回操作-0.751\wd0,因此您可以简化为:

\newcommand{\nhphantom}[1]{\sbox0{#1}\hspace{-0.751\wd0}}

这个寄存器原理构成了 TeX 的内存。TeX 有:

  • \count用于保存计数器(整数)的寄存器;
  • \dimen寄存器用于保存长度;
  • \skip用于容纳胶水的寄存器(一个维度加上另一个维度减去一个维度);
  • \muskip用于保存 muglue 的寄存器(用于数学);
  • \box用于存放箱子的收银机;以及
  • \toks寄存器用于保存标记列表。

至于您关于带星号版本的问题(我现在才看到,抱歉)......

\sbox0{#1}宏中的将\nhphantom内容保存#1\hbox,即不是在数学模式下,因此您必须调用\nhphantomwith$...$来强制执行数学模式。但这会在数学模式下的文本模式下创建数学模式,这会使 TeX “忘记”它所处的方程式的其余部分。

当您使用由 创建的分隔符的星号版本时\DeclarePairedDelimiterX,您使外部分隔符成为\left<delim>\right<delim>,并且\delimsize成为在和\middle之间安全使用。问题是 math-in-text-in-math 会让 TeX 忘记周围的和以及 的参数是,这是无效的,因为您不能在没有封闭 的情况下使用。\left\right\left\right\nhphantom$\middle\lbrack$\middle\left...\right

为了解决这个问题,我\nhphantom稍微修改了一下宏。它现在有两个参数:分隔符和其间的内容。\nhphantom然后宏测量 的宽度\left<delim>\vphantom{#1}\right.,这是有效的。

以下是完整的工作代码:

\documentclass{article}

\usepackage{mathtools}

\DeclarePairedDelimiterX{\dbrackets}[1]{\lbrack}{\rbrack}{
    \nhphantom{\lbrack}{#1} \delimsize\lbrack \mathopen{} #1 \mathclose{} \delimsize\rbrack \nhphantom{\rbrack}{#1}
}
\DeclarePairedDelimiterX{\dbraces}[1]{\lbrace}{\rbrace}{
    \nhphantom{\lbrace}{#1} \delimsize\lbrace \mathopen{} #1 \mathclose{} \delimsize\rbrace \nhphantom{\rbrace}{#1}
}
\DeclarePairedDelimiterX{\dparens}[1]{\lparen}{\rparen}{
    \nhphantom{\lparen}{#1} \delimsize\lparen \mathopen{} #1 \mathclose{} \delimsize\rparen \nhphantom{\rparen}{#1}
}

\newcommand{\nhphantom}[2]{\sbox0{$\left#1\vphantom{#2}\right.$}\hspace{-0.58\wd0}}

\begin{document}

$\dbrackets[\big]{\frac12}$
$\dbraces[\big]{\frac12}$
$\dparens[\big]{\frac12}$

%These do work :)

$\dbrackets*{\frac12}$
$\dbraces*{\frac12}$
$\dparens*{\frac12}$

\end{document}

在此处输入图片描述

答案2

在可接受的答案中,0.58 是一个临时值,手动调整以使其看起来不错。但乘法缩放在这里是错误的;0.58 不适用于\Bigg,也不适用于默认大小的内联数学。更糟糕的是,它对于带星号和不带星号的命令版本的行为不同,因为如果命令发送了特定大小,则测量自动调整大小 \sbox 无济于事。

话虽如此,Phelype 的解决方案确实为我们提供了大部分帮助。我建议对命令进行以下细微修改\nhphantom

\newcommand{\nhphantom}[2]{\sbox0{\kern-2\nulldelimiterspace
      $\left.\delimsize#1\vphantom{#2}\right.$}\hspace{-.97\wd0}}

消除\kearn-2\nulldelimeterspace了 和 的额外(测量!)空间\left.\right.\delimsize扩展到适当的大小,(或到\middle),在 的上下文中\DeclarePairedDelimieterX) 。数字 -.97 也可以用 -1 代替,但我发现 (小的)数量的乘法缩放仍然令人赏心悦目。

现在间距已经精确,我们现在必须添加一个小的附加间距(下面是 1.2pt),即使对于非常大的括号,它也可以缩放。在双括号实例中,

\DeclarePairedDelimiterX{\dbrackets}[1]{\lbrack}{\rbrack}
        {\nhphantom{\lbrack}{#1}\hspace{1.2pt}\delimsize\lbrack\mathopen{}#1\mathclose{}\delimsize\rbrack\hspace{1.2pt}\nhphantom{\rbrack}{#1}}

奖金:这是一个定义变体的简单自动化方法:

% same code as before
\newcommand{\nhphantom}[2]{\sbox0{\kern-2\nulldelimiterspace$\left.\delimsize#1\vphantom{#2}\right.$}\hspace{-.97\wd0}}
    
% very minor wrapper around what we had before
\newcommand\DeclareDoubleDelim[5]{
    \DeclarePairedDelimiterX{#1}[1]{#2}{#5}
        {\nhphantom{#3}{##1}\hspace{1.2pt}\delimsize#3\mathopen{}##1\mathclose{}\delimsize#4\hspace{1.2pt}\nhphantom{#4}{##1}}
}

% examples
\DeclareDoubleDelim \dbrackets [[]] 
\DeclareDoubleDelim \dblbraces \{\{\}\} 
\DeclareDoubleDelim \dblparens (())
\DeclareDoubleDelim \dblangles \langle\langle\rangle\rangle

\[
    \dbrackets*{\frac12} \quad \dblangles*{\frac12} \qquad 
    \dbrackets[\Bigg]{\frac12} \quad \dblangles[\Bigg]{\frac12} \qquad
    \dbrackets{\nicefrac12} \quad \dblangles{\nicefrac12}
\]

第一和最后

相关内容