通过一个命令定义并设置长度

通过一个命令定义并设置长度

抱歉,这可能是一个非常简单的问题,我正在尝试清理样式文件,并想编写一个基本上运行以下代码的命令:

\newlength{<name>}\setlength{<name>}{<value>}

基于运行的另一个命令\def,我认为我可以轻松使用expandaftercsname以下是我尝试过的:

\newcommand{\deflen}[2]{%
    \expandafter\newlength{%
    \csname #1\endcsname}\setlength{%
    \csname #1\endcsname}{#2}
}

不幸的是,这似乎会产生与已定义相关的错误csname。我认为这意味着我不能csname在同一个扩展中使用两次,但我不知道如何先定义名称,然后使用它两次......帮忙?:)

答案1

您需要在用 定义之前\newcommand和使用之前组装控制序列名称。这可以使用\expandafter两次来实现。

\newcommand{\deflen}[2]{%      
    \expandafter\newlength\csname #1\endcsname
    \expandafter\setlength\csname #1\endcsname{#2}%
}

\deflen{mylength}{12pt}

\showthe\mylength

答案2

Ian Thompson 的代码很好,但你可以添加检查首先定义一个新的长度;例如,

\deflen{textwidth}{6pt}

会在 处发出错误消息\newlength,但它\textwidth仍然会设置。由于您处于样式文件中,因此您不需要\makeatletter命令@,因此您可以执行

\newcommand{\deflen}[2]{%
  \expandafter\@ifdefinable\csname #1\endcsname{\prefix@deflen{#1}{#2}}%
}
\newcommand{\prefix@deflen}[2]{%
  \expandafter\newlength\csname #1\endcsname
  \expandafter\setlength\csname #1\endcsname{#2}%
}

仅当第一个参数给出的控制序列未定义时,才会执行作为第二个参数给出的代码\@ifdefinable;否则会引发错误并忽略代码。

请注意,prefix代表样式文件中使用的前缀,用于不破坏其他包的宏。

LaTeX3 版本可能

\RequirePackage{xparse}
\ExplSyntaxOn

\NewDocumentCommand{\deflen}{ s m m }
 {
  \IfBooleanTF { #1 }
   { \prefix_deflen:nnn { dim }  { #2 } { #3 } }
   { \prefix_deflen:nnn { skip } { #2 } { #3 } }
 }

\cs_new_protected:Npn \prefix_deflen:nnn #1 #2 #3
 {
  \cs_if_exist:cTF { #2 }
   {
    \msg_error:nnn { package } { already~defined } { #2 }
   }
   {
    \__prefix_deflen:nnn { #1 } { #2 } { #3 }
   }
 }
\cs_new_protected:Npn \__prefix_deflen:nnn #1 #2 #3
 {
  \use:c { #1_new:c } { l_prefix_#2_#1 }
  \use:c { #1_set:cn } { l_prefix_#2_#1 } { #3 }
  \cs_set_eq:cc { #2 } { l_prefix_#2_#1 } % user level name
 }

\msg_new:nnnn { package } { already~defined }
 {
  Control~sequence~\exp_not:c { #1 } already~defined.
 }
 {
  The~control~sequence~\exp_not:c { #1 } already~exists.~
  Please~use~a~new~name;~the~command~will~not~be~executed.
 }

\ExplSyntaxOff

请注意,\deflen{foo}{6pt}将定义\l_prefix_foo_skip为寄存器的内部名称,但也在\foo用户级别。 *-version 将分配一个固定长度的寄存器(\dimen在 TeXspeak 中为 )。

测试代码:

\deflen{foo}{3pt}
\showthe\foo
\show\foo

\deflen*{baz}{3pt}
\showthe\baz
\show\baz

\deflen{textwidth}{3pt}

这是终端输出:

> 3.0pt.
l.40 \showthe\foo

? 
> \foo=\skip47.
l.41 \show\foo

? 
> 3.0pt.
l.44 \showthe\baz

? 
> \baz=\dimen133.
l.45 \show\baz

? 

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! package error: "already defined"
! 
! Control sequence \textwidth already defined.
! 
! See the package documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.46 \deflen{textwidth}{3pt}

? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| The control sequence \textwidth already exists. Please use a new name; the
| command will not be executed.
|...............................................
? 

相关内容