![向我解释此代码:双重分隔符](https://linux22.com/image/374057/%E5%90%91%E6%88%91%E8%A7%A3%E9%87%8A%E6%AD%A4%E4%BB%A3%E7%A0%81%EF%BC%9A%E5%8F%8C%E9%87%8D%E5%88%86%E9%9A%94%E7%AC%A6.png)
不久前我问过这个问题双重分隔符。我发现这段代码并将其改编为以下内容:
\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
,即不是在数学模式下,因此您必须调用\nhphantom
with$...$
来强制执行数学模式。但这会在数学模式下的文本模式下创建数学模式,这会使 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}
\]