如何定义幻影的深度和高度?

如何定义幻影的深度和高度?

在第三个“危险弯道”第178页TeXbook有以下描述\vphantom

比 更有用\phantom\vphantom它创建一个隐形的盒子,其高度和深度与相应的 \phantom 相同,但宽度为零。

在附录 B(第 360 页)中,可以找到和的定义\vphantom\hphantom\phantom

\newif\ifv@ \newif\ifh@
\def\vphantom{\v@true\h@false\ph@nt}
\def\hphantom{\v@false\h@true\ph@nt}
\def\phantom{\v@true\h@true\ph@nt}
\def\ph@nt{\ifmmode\def\next{\mathpalette\mathph@nt}%
  \else\let\next=\makeph@nt\fi \next}
\def\makeph@nt#1{\setbox0=\hbox{#1}\finph@nt}
\def\mathph@nt#1#2{\setbox0=\hbox{$\m@th#1{#2}$}\finph@nt}
\def\finph@nt{\setbox2=\null \ifv@ \ht2=\ht0 \dp2=\dp0 \fi
  \ifh@ \wd2=\wd0 \fi \box2 }

ltmath.dtx以下是 LaTeX 内核 ( ,第 256 页)中的定义source2e.pdf

\newif\ifv@
\newif\ifh@
\def\vphantom{\v@true\h@false\ph@nt}
\def\hphantom{\v@false\h@true\ph@nt}
\def\phantom{\v@true\h@true\ph@nt}
\def\ph@nt{%
  \ifmmode
    \expandafter\mathpalette\expandafter\mathph@nt
  \else
    \expandafter\makeph@nt
  \fi}
\def\makeph@nt#1{%
  \setbox\z@\hbox{\color@begingroup#1\color@endgroup}\finph@nt}
\def\mathph@nt#1#2{%
  \setbox\z@\hbox{$\m@th#1{#2}$}\finph@nt}
\def\finph@nt{%
  \setbox\tw@\null
  \ifv@ \ht\tw@\ht\z@ \dp\tw@\dp\z@\fi
  \ifh@ \wd\tw@\wd\z@\fi \box\tw@}

由于\vphantom保留了总高度(=高度+深度),我想知道为什么没有仅深度和仅高度的幻像?更准确地说,上述定义如何扩展以定义\dphantom(仅用于深度)和\htphantom(仅用于高度)?前者会产生一个不可见的盒子,其深度与对应的相同\phantom,但其宽度和高度为零,后者将产生一个不可见的盒子,其高度与相应的相同,\phantom但其宽度和深度为零。

答案1

例如,\ifv@可以将开关拆分为高度和深度两个开关:\ifv@ht@\ifv@dp@

宏以这种方式改变(未改变的宏被注释掉):

纯 TeX

% \newif\ifh@            
\newif\ifv@ht@ \newif\ifv@dp@
\def\vphantom {\v@ht@true \v@dp@true \h@false\ph@nt}
\def\hphantom {\v@ht@false\v@dp@false\h@true \ph@nt}
\def\htphantom{\v@ht@true \v@dp@false\h@false\ph@nt}  
\def\dpphantom{\v@ht@false\v@dp@true \h@false\ph@nt}  
\def\phantom  {\v@ht@true \v@dp@true \h@true \ph@nt}      
%\def\ph@nt{\ifmmode\def\next{\mathpalette\mathph@nt}%
%  \else\let\next=\makeph@nt\fi \next}
%\def\makeph@nt#1{\setbox0=\hbox{#1}\finph@nt}
%\def\mathph@nt#1#2{\setbox0=\hbox{$\m@th#1{#2}$}\finph@nt}
\def\finph@nt{%
  \setbox2=\null
  \ifv@ht@ \ht2=\ht0 \fi
  \ifv@dp@ \dp2=\dp0 \fi  
  \ifh@ \wd2=\wd0 \fi   
  \box2 %
}

% Macro \test, which visualizes the bounding box
\def\test#1#2{%
  \leavevmode
  \hbox{%  
    \vrule  
    \vbox{%  
      \hrule 
      \vtop{%
        \hbox{#1{#2}}%
        \hrule
      }%
    }%
    \vrule
  }%
}

g \test\phantom{g} \test\hphantom{g} \test\vphantom{g}
\test\htphantom{g} \test\dpphantom{g}
\bye

测试结果

乳胶

LaTeX 从纯 TeX 继承了这些宏。它只做了一些改变\makeph@nt以添加颜色支持。但此命令无需更改。以下示例为 LaTeX 重新定义了这些宏:

\documentclass{article}

\makeatletter
\newif\ifv@ht@ \newif\ifv@dp@
\renewcommand*{\vphantom} {\v@ht@true \v@dp@true \h@false\ph@nt}
\renewcommand*{\hphantom} {\v@ht@false\v@dp@false\h@true \ph@nt}
\newcommand*  {\htphantom}{\v@ht@true \v@dp@false\h@false\ph@nt}
\newcommand*  {\dpphantom}{\v@ht@false\v@dp@true \h@false\ph@nt}
\renewcommand*{\phantom}  {\v@ht@true \v@dp@true \h@true \ph@nt}
\renewcommand*{\finph@nt}{%
  \setbox2=\null
  \ifv@ht@ \ht2=\ht0 \fi
  \ifv@dp@ \dp2=\dp0 \fi
  \ifh@ \wd2=\wd0 \fi
  \box2 %
}
\makeatother

\begin{document}
  % Macro \test visualizes the bounding box
  \newcommand*{\test}[2]{%
    \begingroup
      \setlength{\fboxsep}{0pt}%
      \fbox{#1{#2}}%
    \endgroup
  }
  g \test\phantom{g} \test\hphantom{g} \test\vphantom{g}
  \test\htphantom{g} \test\dpphantom{g}
\end{document}

结果

答案2

amsmath可以定义

\newcommand{\heightphantom}[1]{\vphantom{\smash[b]{#1}}
\newcommand{\depthphantom}[1]{\vphantom{\smash[t]{#1}}

不如 Heiko 的那么高效,但定义起来更简单。


expl3具有键值接口的版本。如果*确实需要,命令的 -version 不会强制水平模式。

键指定要保留哪些尺寸;不指定任何尺寸意味着保留所有三个尺寸(高度、深度和宽度)。因此,\xphantom{g}主要相当于\phantom{g}(除了自动的\leavevmode),而\xphantom[width]{g}和分别\xphantom[totalheight]{g}相当于\hphantom和。为这些提供了\vphantom简写\xhphantom和。\xvphantom

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\xphantom}{som}
 {% #2 is a list of key-value options, #3 is the text
  \IfBooleanF{#1}{\leavevmode}
  \IfNoValueTF{#2}
   {
    \manual_phantom:nn { totalheight , width } { #3 }
   }
   {
    \manual_phantom:nn { #2 } { #3 }
   }
 }
\NewDocumentCommand{\xhphantom}{sm}
 {
  \IfBooleanTF{#1}
   {
    \xphantom*[width]{#2}
   }
   {
    \xphantom[width]{#2}
   }
 }
\NewDocumentCommand{\xvphantom}{sm}
 {
  \IfBooleanTF{#1}
   {
    \xphantom*[totalheight]{#2}
   }
   {
    \xphantom[totalheight]{#2}
   }
 }

\keys_define:nn { manual/xphantom }
 {
  height .bool_set:N  = \l__manual_phantom_keepht_bool,
  depth  .bool_set:N  = \l__manual_phantom_keepdp_bool,
  width  .bool_set:N  = \l__manual_phantom_keepwd_bool,
  totalheight .code:n = 
    \bool_set_true:N \l__manual_phantom_keepht_bool
    \bool_set_true:N \l__manual_phantom_keepdp_bool,
  height .default:n = true,
  depth  .default:n = true,
  width  .default:n = true,
  totalheight .default:n = ,
 }

\box_new:N \l__manual_phantom_input_box
\box_new:N \l__manual_phantom_box

\cs_new_protected:Npn \manual_phantom:nn #1 #2
 {
  \group_begin:
  \keys_set:nn { manual/xphantom } { #1 }
  \hbox_set:Nn \l__manual_phantom_input_box { #2 }
  \hbox_set:Nn \l__manual_phantom_box {}
  \bool_if:NT \l__manual_phantom_keepht_bool
   {
    \box_set_ht:Nn \l__manual_phantom_box { \box_ht:N \l__manual_phantom_input_box }
   }
  \bool_if:NT \l__manual_phantom_keepdp_bool
   {
    \box_set_dp:Nn \l__manual_phantom_box { \box_dp:N \l__manual_phantom_input_box }
   }
  \bool_if:NT \l__manual_phantom_keepwd_bool
   {
    \box_set_wd:Nn \l__manual_phantom_box { \box_wd:N \l__manual_phantom_input_box }
   }
  \box_use:N \l__manual_phantom_box
  \group_end:
 }
\ExplSyntaxOff

\begin{document}

\newcommand*{\test}[1]{%
  \begingroup
    \setlength{\fboxsep}{0pt}%
    \fbox{#1}%
  \endgroup
}

g
\test{\xphantom{g}}
\test{\xphantom[width]{g}}
\test{\xphantom[totalheight]{g}}
\test{\xphantom[height]{g}}
\test{\xphantom[depth]{g}}

g
\test{\xphantom[height,width]{g}}
\test{\xphantom[depth,width]{g}}

g
\test{\xhphantom{g}}
\test{\xvphantom{g}}

\end{document}

在此处输入图片描述


还实现数学模式的版本:

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

\ExplSyntaxOn
\NewDocumentCommand{\xphantom}{som}
 {% #2 is a list of key-value options, #3 is the text
  \IfBooleanF{#1}{ \mode_if_math:F { \leavevmode } }
  \IfNoValueTF{#2}
   {
    \manual_phantom:nn { totalheight , width } { #3 }
   }
   {
    \manual_phantom:nn { #2 } { #3 }
   }
 }
\NewDocumentCommand{\xhphantom}{sm}
 {
  \IfBooleanTF{#1}
   {
    \xphantom*[width]{#2}
   }
   {
    \xphantom[width]{#2}
   }
 }
\NewDocumentCommand{\xvphantom}{sm}
 {
  \IfBooleanTF{#1}
   {
    \xphantom*[totalheight]{#2}
   }
   {
    \xphantom[totalheight]{#2}
   }
 }

\keys_define:nn { manual/xphantom }
 {
  height .bool_set:N  = \l__manual_phantom_keepht_bool,
  depth  .bool_set:N  = \l__manual_phantom_keepdp_bool,
  width  .bool_set:N  = \l__manual_phantom_keepwd_bool,
  totalheight .code:n = 
    \bool_set_true:N \l__manual_phantom_keepht_bool
    \bool_set_true:N \l__manual_phantom_keepdp_bool,
  height .default:n = true,
  depth  .default:n = true,
  width  .default:n = true,
  totalheight .default:n = ,
 }

\box_new:N \l__manual_phantom_input_box
\box_new:N \l__manual_phantom_box

\cs_new_protected:Npn \manual_phantom:nn #1 #2
 {
  \group_begin:
  \keys_set:nn { manual/xphantom } { #1 }
  \hbox_set:Nn \l__manual_phantom_box {}
  \mode_if_math:TF
    {
     \__manual_phantom_math:n { #2 }
    }
    {
     \hbox_set:Nn \l__manual_phantom_input_box { #2 }
     \__manual_phantom_set:
    }
  \group_end:
 }
\cs_new_protected:Npn \__manual_phantom_set:
 {
  \bool_if:NT \l__manual_phantom_keepht_bool
   {
    \box_set_ht:Nn \l__manual_phantom_box { \box_ht:N \l__manual_phantom_input_box }
   }
  \bool_if:NT \l__manual_phantom_keepdp_bool
   {
    \box_set_dp:Nn \l__manual_phantom_box { \box_dp:N \l__manual_phantom_input_box }
   }
  \bool_if:NT \l__manual_phantom_keepwd_bool
   {
    \box_set_wd:Nn \l__manual_phantom_box { \box_wd:N \l__manual_phantom_input_box }
   }
  \box_use:N \l__manual_phantom_box
 }

% Now math mode; there's currently no syntactic sugar for \mathpalette
\cs_new_protected:Npn \__manual_phantom_math:n #1
 {
  \mathpalette \__manual_make_phantom_math:nn { #1 }
 }
\cs_new_protected:Npn \__manual_make_phantom_math:nn #1 #2
 {
  \hbox_set:Nn \l__manual_phantom_input_box { $ #1 {#2} \mathsurround=0pt $ }
  \__manual_phantom_set:
 }
\ExplSyntaxOff

\begin{document}

\newcommand*{\test}[1]{%
  \begingroup
    \setlength{\fboxsep}{0pt}%
    \fbox{#1}%
  \endgroup
}

g
\test{\xphantom{g}}
\test{\xphantom[width]{g}}
\test{\xphantom[totalheight]{g}}
\test{\xphantom[height]{g}}
\test{\xphantom[depth]{g}}

g
\test{\xphantom[height,width]{g}}
\test{\xphantom[depth,width]{g}}

g
\test{\xhphantom{g}}
\test{\xvphantom{g}}

$\displaystyle\sum$
\test{$\displaystyle\xphantom{\sum}$}
\test{$\displaystyle\xvphantom{\sum}$}
\test{$\displaystyle\xhphantom{\sum}$}
\test{$\displaystyle\xphantom[height]{\sum}$}
\test{$\displaystyle\xphantom[depth]{\sum}$}
\test{$\displaystyle\xphantom[height,width]{\sum}$}
\test{$\displaystyle\xphantom[depth,width]{\sum}$}

$\textstyle\sum$
\test{$\textstyle\xphantom{\sum}$}
\test{$\textstyle\xvphantom{\sum}$}
\test{$\textstyle\xhphantom{\sum}$}

$\scriptstyle\sum$
\test{$\scriptstyle\xphantom{\sum}$}
\test{$\scriptstyle\xvphantom{\sum}$}
\test{$\scriptstyle\xhphantom{\sum}$}

$\scriptscriptstyle\sum$
\test{$\scriptscriptstyle\xphantom{\sum}$}
\test{$\scriptscriptstyle\xvphantom{\sum}$}
\test{$\scriptscriptstyle\xhphantom{\sum}$}

\end{document}

在此处输入图片描述

答案3

这不会扩展现有\vphantom定义,但提供了替代方案。它适用于文本模式以及所有数学模式。已编辑以删除对 的包依赖scalerel,但保留的\thisstyle\savedstyle定义在很大程度上模仿了包(\ThisStyle\SavedStyle)中的定义。已编辑以添加\wdphantom\htwdphantom\dpwdphantom

\documentclass{article}
\makeatletter
\def\@mstyleD{\displaystyle}
\def\@mstyleT{\textstyle}
\def\@mstyleS{\scriptstyle}
\def\@mstyles{\scriptscriptstyle}
\let\@mstyleX\relax
\def\savedstyle{\csname @mstyle\m@switch\endcsname}
%
\def\thisstyle#1{%
  \ifmmode\mathchoice%
      {\edef\m@switch{D}#1}{\edef\m@switch{T}#1}{\edef\m@switch{S}#1}{\edef\m@switch{s}#1}%
  \else\edef\m@switch{X}#1\fi%
}
\makeatother
\def\preservebox#1{\thisstyle{\setbox0=\hbox{\savedstyle#1}}}
\def\htphantom#1{\preservebox{#1}\rule{0pt}{\ht0}}
\def\dpphantom#1{\preservebox{#1}\rule[-\dp0]{0pt}{\dp0}}
\def\wdphantom#1{\preservebox{#1}\rule{\wd0}{0pt}}
\def\htwdphantom#1{\preservebox{#1}\rule{0pt}{\ht0}\rule{\wd0}{0pt}}
\def\dpwdphantom#1{\preservebox{#1}\rule[-\dp0]{0pt}{\dp0}\rule{\wd0}{0pt}}
\def\test#1{#1 \fbox{\phantom{#1}} \fbox{\vphantom{#1}} 
  \fbox{\wdphantom{#1}} \fbox{\htphantom{#1}} \fbox{\dpphantom{#1}}
    \fbox{\htwdphantom{#1}} \fbox{\dpwdphantom{#1}} \par}
\fboxsep=0pt\relax\fboxrule=.2pt
\begin{document}
\test{g}\test{$g$}\test{$\scriptscriptstyle g$}\test{\Large g}
\test{$\sum_{i=1}^N$}
\test{$\displaystyle\sum_{i=1}^N$}
\end{document}

在此处输入图片描述

相关内容