如何连接 2 个长度

如何连接 2 个长度

我真的很想创建一个默认长度,即使\bar长度发生变化,它也与原长度相同,但我还希望用户能够将其设置为他们想要的任何长度。如果我使用宏而不是长度,我可以接近这个效果,但用户需要小心使用。最好的方法是什么?\foo\foo\bar\bar\baz

在此处输入图片描述

\documentclass{article}
\let\bar\relax
\newlength{\foo}
\newlength{\bar}\setlength{\bar}{\foo}
\newlength{\qux}
\def\baz{\foo}

\begin{document}
\setlength{\foo}{100pt}\bigskip
foo: \the\foo\par bar: \the\bar\par baz: \the\baz\par

\setlength{\foo}{2\baz}\bigskip
foo: \the\foo\par bar: \the\bar\par baz: \the\baz\par

\def\baz{400pt}
\setlength{\qux}{2\baz}\bigskip
% Note that \baz no long works with \the
foo: \the\foo\par bar: \the\bar\par baz: \baz\par
% Note that \qux is "wrong"
qux: \the\qux\par
\end{document}

答案1

这是我在计数器包中使用的类似方法xassoccnt:将长度与“主”长度关联,比如“\foo”。

如果\foo为 分配了一个新值\setlength,则与其关联的所有长度都将获得相同的值。

我定义了\addtolength等,以及删除和同步。星号版本的\setlength\addtolength将仅操纵主长度!

但是,直接操作对等\foo不起作用。\baz

\documentclass{article}


\usepackage{xparse}

\makeatletter
\let\latex@setlength\setlength
\let\latex@addtolength\addtolength

\newcommand{\stripslash}[1]{%
  \expandafter\@gobble\string#1
}

\ExplSyntaxOn

\cs_new:Nn \strongbad_associate_lengths:nn {%
  \seq_set_from_clist:cn {g_strongbad_#1_lengths_seq} {#2} % Populate unexpanded
  \seq_remove_duplicates:c {g_strongbad_#1_lengths_seq}
  \seq_remove_all:cn {g_strongbad_#1_lengths_seq} {#1}% Prevent self - association!
  \seq_map_inline:cn {g_strongbad_#1_lengths_seq} {
    \dim_if_exist:NF { ##1 } {% Preventing complaining about already existing length variables
      \newlength{##1}
    }
  }
}


\NewDocumentCommand{\RemoveAssociatedLengths}{mm}{%
  \seq_if_exist:cT { g_strongbad_ \stripslash{#1} _lengths_seq } {
    \seq_set_from_clist:Nn \l_tmpa_seq {#2}
    \seq_map_inline:Nn \l_tmpa_seq {
      \seq_remove_all:cn { g_strongbad_ \stripslash{#1} _lengths_seq } {##1}
    }
  }
}

\NewDocumentCommand{\DeclareAssociatedLength}{mm}{%
  \strongbad_add_associated_length:nn {#1}{#2}
}

\cs_new:Nn \strongbad_add_associated_length:nn {%
  \seq_if_exist:cF { g_strongbad_\stripslash{#1}_lengths_seq} {
    \seq_new:c {g_strongbad_\stripslash{#1}_lengths_seq}
  }
  \strongbad_associate_lengths:nn{\stripslash{#1}}{#2}
}


\NewDocumentCommand{\AddAssociatedLengths}{mm}{%
  \strongbad_associate_lengths:nn{\stripslash{#1}}{#2}  
}

\RenewDocumentCommand{\addtolength}{smm}{%
  \IfBooleanF{#1}{% No starred command
    \seq_if_exist:cT { g_strongbad_ \stripslash{#2} _lengths_seq } {
      \seq_map_inline:cn {  g_strongbad_ \stripslash{#2} _lengths_seq } {
        \latex@addtolength{##1}{#3}
      }% End of \seq_map_inline
    }% End of \seq_if_exist
  }% End of \IfBooleanF
  \latex@addtolength{#2}{#3}
}

\NewDocumentCommand{\synclengths}{m}{%
  \seq_if_exist:cT { g_strongbad_ \stripslash{#1} _lengths_seq } {
    \dim_set:Nn \l_tmpa_dim {\the#1}
    \setlength{#1}{\l_tmpa_dim}
  }
}

\NewDocumentCommand{\syncaddtolength}{mm}{%
  \addtolength*{#1}{#2}%
  \synclengths{#1}%
}


\RenewDocumentCommand{\setlength}{smm}{%
  \IfBooleanF{#1}{% No starred command
    \seq_if_exist:cT { g_strongbad_ \stripslash{#2} _lengths_seq } {
      \seq_map_inline:cn {  g_strongbad_ \stripslash{#2} _lengths_seq } {
        \latex@setlength{##1}{#3}
      }% End of \seq_map_inline
    }% End of \seq_if_exist
  }% End of \IfBooleanF
  \latex@setlength{#2}{#3}
}

\makeatother


\ExplSyntaxOff

\begin{document}

\newlength{\foo}

\newlength{\boz}

\DeclareAssociatedLength{\foo}{\baz,\buz,\boz,\biz}

\setlength{\foo}{100pt}


foo: \the\foo

baz: \the\baz

buz: \the\buz

boz: \the\boz

biz: \the\biz

\setlength{\baz}{\dimexpr200pt+\foo}

Foo again: \the\foo

Baz now: \the\baz

buz: \the\buz

boz: \the\boz

biz: \the\biz

Now using the starred version:

\setlength*{\foo}{5000pt}

Foo after starred version: \the\foo

Baz after starred version: \the\baz


Adding some value:

\addtolength{\foo}{100pt}

Foo after adding some value: \the\foo

Baz after adding some value to foo: \the\baz


Adding some value with synchronization first:

\syncaddtolength{\foo}{100pt}

Foo after adding some value: \the\foo

Baz after adding some value to foo: \the\baz

Buz after adding some value to foo: \the\buz

Removing buz and biz:

\RemoveAssociatedLengths{\foo}{\buz,\biz}

\addtolength{\foo}{-1000pt}

New foo: \the\foo

New biz: \the\biz

New buz: \the\buz



\end{document}

在此处输入图片描述

答案2

\baz扩展为\foo,这是一个长度,因此2\baz在第二个长度设置中有效。但是,让\def\baz{400pt}不再产生\baz长度。是的,从技术上讲,它会扩展为有效长度,但不能按原样用于长度乘积。您必须明确使用\dimexpr,否则值将被连接而不是相乘:

在此处输入图片描述

\documentclass{article}

\let\bar\relax% Just for this example

\newlength{\foo}% \foo is a length
\newlength{\bar}\setlength{\bar}{\foo}% \bar is a length
\newlength{\qux}% \qux is a length
\def\baz{\foo}% \baz expands to \foo, which is a length

\begin{document}

\setlength{\foo}{100pt}\bigskip
foo: \the\foo\par bar: \the\bar\par baz: \the\baz\par

\setlength{\foo}{2\baz}\bigskip
foo: \the\foo\par bar: \the\bar\par baz: \the\baz\par

\def\baz{400pt}% \baz is no longer a length
\setlength{\qux}{2\dimexpr\baz}\bigskip
foo: \the\foo\par bar: \the\bar\par baz: \the\dimexpr\baz\par
qux: \the\qux\par

\end{document}

狡猾一点的一点是,你可以

\def\baz{\dimexpr400pt}

答案3

您可以创建链接长度,但需要不同的命令(或覆盖标准命令)。语法类似于\newcounter

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\NewLength}{mo}
 {
  \newlength{#1}
  \seq_new:c { g_strongbad_length_ \cs_to_str:N #1 _seq }
  \IfValueT{#2}
   {
    \seq_gput_right:cn { g_strongbad_length_ \cs_to_str:N #2 _seq } { #1 }
   }
 }
\NewDocumentCommand{\SetLength}{mm}
 {
  \setlength{#1}{#2}
  \seq_map_inline:cn { g_strongbad_length_ \cs_to_str:N #1 _seq }
   {
    \setlength{##1}{#2}
   }
 }
\ExplSyntaxOff

\NewLength{\foo}
\NewLength{\baz}[\foo]
\NewLength{\qux}

\begin{document}

\SetLength{\foo}{100pt}\bigskip
foo: \the\foo\par baz: \the\baz\par

\SetLength{\foo}{2\baz}\bigskip
foo: \the\foo\par baz: \the\baz\par

\SetLength{\baz}{10pt}\bigskip
foo: \the\foo\par baz: \the\baz\par

\SetLength\baz{400pt}
\SetLength{\qux}{2\baz}\bigskip
qux: \the\qux\par

\end{document}

每个定义的长度都有一个关联的长度列表,一旦修改(使用\SetLength),这些长度将设置为与主长度相同的值。我留给你作为练习来实现\AddToLength

在此处输入图片描述

答案4

假设我想要一个长度为 2 倍\foo减 3 pt 的长度。使用长度来定义它(如 的情况\barr),它在定义时是固定的,因此 的后续更改\foo不会对 产生影响\barr

但是,使用\def以 开头的\dimexpr(例如 的情况\baz)允许\foo\baz永久链接到 x2 - 3pt 关系,即使\foo发生变化。此外,\baz充当长度,即使它不是,因此\the\dimexpr3\baz产生预期的长度结果。

\documentclass{article}

\newlength\foo
\newlength\barr
\setlength\foo{100pt}
\setlength\barr{\dimexpr2\foo-3pt}
\def\baz{\dimexpr2\foo-3pt\relax}
\begin{document}
\the\foo, \the\barr, \the\baz

\setlength\foo{200pt}
\the\foo, \the\barr, \the\baz

\the\dimexpr3\baz

\end{document}

在此处输入图片描述

跟进

问题是这种\dimexpr方法如何处理胶水。答案是可以的,如果\relax用于终止\dimexpr 加入胶水。因此,

\documentclass{article}

\newlength\foo
\setlength\foo{100pt}
\def\baz{\dimexpr2\foo-3pt\relax minus20pt}
\begin{document}

\foo=100pt\relax

x\hspace{\baz}x

x\hspace{197pt minus 20pt}x

x\hspace{197pt}x

\noindent\hrulefill

\foo=165pt\relax

x\hspace{\baz}x

x\hspace{327pt minus 20pt}x

x\hspace{327pt}x

\end{document}

在此处输入图片描述

可以看出,胶水在的扩展中起作用\baz

相关内容