\smashoperator 如何剪辑限制脚本的空间?

\smashoperator 如何剪辑限制脚本的空间?

已经存在关于如何水平突破数学运算符限制的问题,例如改进长限制和的排版,结论是“使用包\smashoperator中的命令mathtools”。

我正在尝试了解这个宏的工作原理。不幸的是,实施expl3模糊的,因此很难理解。代码上有一些注释,但几乎没有关于如何使用内部宏的描述。到目前为止,我所理解的是,\smashoperator首先分析其强制参数,并将其拆分为上标、下标和其他一些可选代码。

我不明白的是,操作符实际上是如何排版的,脚本仅在左侧、右侧或两侧被破坏。有人可以用 TeX/LaTeX2e 代码解释命令的这一部分是如何实现的吗?

答案1

首先:

\newcommand*\smashoperator[2][lr]{
  \def\MT_smop_use:NNNNN {\@nameuse{MT_smop_smash_#1:NNNNN}}
  \toks@{#2}
  \expandafter\MT_smop_get_args:wwwNnNn
    \the\toks@\@nil\@nil\@nil\@nil\@nil\@nil\@@nil
}

调用时\smashoperator{\sum_{a}^{b}},宏\MT_smop_use:NNNNN被定义为扩展为\MT_smop_smash_lr:NNNNN,参数被加载到令牌寄存器中\toks@。目前还不清楚为什么要做这个中间步骤,因为令牌寄存器的内容会立即被传递,我们得到

\MT_smop_get_args:wwwNnNn \sum_{a}^{b}\@nil\@nil\@nil\@nil\@nil\@nil\@@nil

的目的\MT_smop_get_args:wwwNnNn是用很长的代码来标识操作符、下标和上标。然后将上标和下标设置在具有适当狭窄样式的框中,并放置在上方和下方,但占用零宽度。

更简单的实现如下xparse

\documentclass{article}
\usepackage{mathtools,xparse}

\NewDocumentCommand{\xsmashoperator}{me{_^}}{%
  \doxsmashoperator{#1}{#2}{#3}%
}

\ExplSyntaxOn

\NewDocumentCommand{\doxsmashoperator}{mmm}
 {
  #1
  \IfValueT{#2}{\sb{\mathclap{\cramped{#2}}}}
  \IfValueT{#3}{\sp{\mathclap{\cramped{#3}}}}
 }

\ExplSyntaxOff

\begin{document}

\begin{gather*}
XXXX\smashoperator{\sum_{k=12345^2}^{123456789}}YYYYYY \\
XXXX\xsmashoperator\sum_{k=12345^2}^{123456789}YYYYYY
\end{gather*}

\end{document}

在此处输入图片描述

l实现和选项会更加复杂r,但主要要素已经存在,即如何吸收可选的下标和上标,甚至不需要额外的括号(版本中不允许xparse)。

请注意,\ExplSyntaxOn和不是必需的;它们是根据和\ExplSyntaxOff的实现来使用的。lr

基本上,需要进行测量,并添加必要的前后间距。让斯普某人操作分别为上标、下标和运算符的宽度。然后,将运算符设置为其正常宽度,上标/下标的宽度为零。如果r设置了,则宽度为 max(0pt, max(斯普某人) -操作)/2 添加在运算符之前;如果l设置了,则添加在运算符之后。

这是一个完整的实现:

\documentclass{article}
\usepackage{mathtools,xparse}

\NewDocumentCommand{\xsmashoperator}{ome{_^}}{%
  \IfNoValueTF{#1}
   {%
    \doxsmashoperator{#2}{#3}{#4}%
   }
   {%
    \doxsmashoperatoropt{#1}{#2}{#3}{#4}%
   }
}

\ExplSyntaxOn

\NewDocumentCommand{\doxsmashoperator}{mmm}
 {
  #1
  \IfValueT{#2}{\sb{\mathclap{\cramped{#2}}}}
  \IfValueT{#3}{\sp{\mathclap{\cramped{#3}}}}
 }

\NewDocumentCommand{\doxsmashoperatoropt}{mmmm}
 {
  \group_begin:
  \__siracusa_xsmashoperator:nnnn { #1 } { #2 } { #3 } { #4 }
  \group_end:
 }

\box_new:N \l__siracusa_xsmashoperator_op_box
\box_new:N \l__siracusa_xsmashoperator_sb_box
\box_new:N \l__siracusa_xsmashoperator_sp_box
\dim_new:N \l__siracusa_xsmashoperator_dim

\cs_new_protected:Nn \__siracusa_xsmashoperator_math:n
 {
  $ \use:c { m@th } #1 $
 }

\cs_new_protected:Nn \__siracusa_xsmashoperator:nnnn
 {
  \hbox_set:Nn \l__siracusa_xsmashoperator_op_box
   {
    \__siracusa_xsmashoperator_math:n { \displaystyle{#2} }
   }
  \hbox_set:Nn \l__siracusa_xsmashoperator_sb_box
   {
    \tl_if_novalue:nF { #3 }{ \__siracusa_xsmashoperator_math:n {\scriptstyle\cramped{#3}} }
   }
  \hbox_set:Nn \l__siracusa_xsmashoperator_sp_box
   {
    \tl_if_novalue:nF { #4 }{ \__siracusa_xsmashoperator_math:n {\scriptstyle\cramped{#4}} }
   }
  \dim_set:Nn \l__siracusa_xsmashoperator_dim
   {
    \dim_max:nn
     { \box_wd:N \l__siracusa_xsmashoperator_sp_box }
     { \box_wd:N \l__siracusa_xsmashoperator_sb_box }
    - \box_wd:N \l__siracusa_xsmashoperator_op_box
   }
  \dim_set:Nn \l__siracusa_xsmashoperator_dim
   {
    \dim_max:nn { \l__siracusa_xsmashoperator_dim } { 0pt } / 2
   }
  % now do the typesetting
  \str_if_eq:nnT { #1 } { r } { \hspace{\l__siracusa_xsmashoperator_dim} }
  #2
  \tl_if_novalue:nF { #3 } { \sb{\mathclap{\cramped{#3}}} }
  \tl_if_novalue:nF { #4 } { \sp{\mathclap{\cramped{#4}}} }
  \str_if_eq:nnT { #1 } { l } { \hspace{\l__siracusa_xsmashoperator_dim} }
 }

\ExplSyntaxOff

\begin{document}

\begin{gather*}
XXXX\smashoperator{\sum_{k=12345^2}^{123456789}}YYYYYY \\
XXXX\xsmashoperator\sum_{k=12345^2}^{123456789}YYYYYY \\
XXXX\smashoperator[l]{\sum_{k=12345^2}^{123456789}}YYYYYY \\
XXXX\xsmashoperator[l]\sum_{k=12345^2}^{123456789}YYYYYY \\
XXXX\smashoperator[r]{\sum_{k=12345^2}^{123456789}}YYYYYY \\
XXXX\xsmashoperator[r]\sum_{k=12345^2}^{123456789}YYYYYY
\end{gather*}

\end{document}

在此处输入图片描述

相关内容