可重复使用的新长度(如果长度已定义则不会停止/中断)

可重复使用的新长度(如果长度已定义则不会停止/中断)

我经常有单独的 .tikz 文件,其中可能包含类似\newlength{\mytmplen}; 的内容,由于我对名称不是很有独到的见解,因此相同的语句最终会出现在多个这样的文件中。如果我想将所有这些文件都包含在一个 .tex 文档中,那么在第二个\newlength具有相同参数的文件上,编译过程将停止并显示以下内容:

! LaTeX Error: Command \mytmplen already defined.
               Or name \end... illegal, see p.192 of the manual.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.30 \newlength{\mytmplen}

? 

因此,我想到设计一个新的 newlength 命令,如果不存在,它会定义新的长度;但如果存在,它只会输入一条消息并继续。

显然,我必须有一种方法来检查命令是否存在;并且可能有一种mytmplen从命令令牌(例如)获取命令名称(例如\mytmplen)的方法。到目前为止,我发现这些帖子相关:

我将在下面发布我的解决方案作为答案;当然,如果能提供更正或替代方法来解决这个问题,我将非常感激!

答案1

您的答案似乎有效。一种更简单的方法可能是首先\let将相关长度变量 -ting 到\relax,然后应用于\newlength它。换句话说,如果您不记得某个宏名称是否曾经用于表示长度参数(或其他任何东西,真的!)并且如果您无论如何都愿意(重新)使用它,您可以先将\let其 -ting 到\relax,然后发出\newlength指令。

\documentclass{article}
\begin{document}

\newlength\mytmplen
\setlength\mytmplen{10pt}
\the\mytmplen

\let\mytmplen\relax % let \mytmplen to \relax

\newlength\mytmplen % now it's safe to "re-issue" it as a length 
\setlength\mytmplen{20pt}
\the\mytmplen

\end{document}

enter image description here

答案2

这里有一条\providelength命令,如果尚未定义,它将定义一个新的长度,但也会检查作为参数传递的命令是否已用 定义\newlength,以便在您尝试使用 时发出错误消息\providelength{\textit}

\documentclass{article}

\makeatletter
\newcommand{\providelength}[1]{%
  \@ifundefined{\expandafter\@gobble\string#1}
   {% if #1 is undefined, do \newlength
    \typeout{\string\providelength: making new length \string#1}%
    \newlength{#1}%
   }
   {% else check whether #1 is actually a length
    \sdaau@checkforlength{#1}%
   }%
}

\newcommand{\sdaau@checkforlength}[1]{%
  % get the first five characters from \meaning#1
  \edef\sdaau@temp{\expandafter\sdaau@getfive\meaning#1TTTTT$}%
  % compare with the string "\skip"
  \ifx\sdaau@temp\sdaau@skipstring
    \typeout{\string\providelength: \string#1 already a length}%
  \else
    \@latex@error
      {\string#1 illegal in \string\providelength}
      {\string#1 is defined, but not with \string\newlength}%
  \fi
}
\def\sdaau@getfive#1#2#3#4#5#6${#1#2#3#4#5}
\edef\sdaau@skipstring{\string\skip}
\makeatother

\begin{document}

\providelength{\foo}
\providelength{\foo}
\providelength{\textit}

\stop

以下是终端输出:

\providelength: making new length \foo
\providelength: \foo already a length

! LaTeX Error: \textit illegal in \providelength.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.31 \providelength{\textit}

? h
\textit is defined, but not with \newlength
? 

带有 的版本expl3,避免了查找命令是否已经有长度的技巧。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\providelength}{m}
 {
  \cs_if_exist:NTF #1
   {
    \sdaau_providelength_check:N #1
   }
   {
    \msg_info:nnx { providelength } { making } { \token_to_str:N #1 }
    \newlength{#1}
   }
 }
\cs_new_protected:Nn \sdaau_providelength_check:N
 {
  \token_if_skip_register:NTF #1
   {
    \msg_info:nnx { providelength } { not-making } { \token_to_str:N #1 }
   }
   {
    \msg_error:nnx { providelength } { defined } { \token_to_str:N #1 }
   }
 }
\msg_new:nnn { providelength } { making }
 {
  \token_to_str:N \providelength :~making~new~length~#1
 }
\msg_new:nnn { providelength } { not-making }
 {
  \token_to_str:N \providelength :~#1~is~already~a~length
 }
\msg_new:nnnn { providelength } { defined }
 {
  #1~illegal~in~\token_to_str:N\providelength
 }
 {
  #1~is~defined,~but~not~with~\token_to_str:N\newlength
 }
\ExplSyntaxOff

\begin{document}

\providelength{\foo}
\providelength{\foo}
\providelength{\textit}

\stop

这是日志文件的摘录

.................................................
. providelength info: "making"
. 
. \providelength: making new length \foo
.................................................
\foo=\skip49
.................................................
. providelength info: "not-making"
. 
. \providelength: \foo is already a length
.................................................


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! providelength error: "defined"
! 
! \textit illegal in \providelength
! 
! See the providelength documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.47 \providelength{\textit}

? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| \textit is defined, but not with \newlength
|...............................................

答案3

好的,因此我首先查找了定义\newlength并进一步使用texdef

$ texdef -t latex \newlength

\newlength:
macro:#1->\@ifdefinable #1{\newskip #1}

$ texdef -t latex \@ifdefinable

\@ifdefinable:
\long macro:#1#2->\edef \reserved@a {\expandafter \@gobble \string #1}\@ifundefined \reserved@a {\edef \reserved@b {\expandafter \@carcube \reserved@a xxx\@nil }\ifx \reserved@b \@qend \@notdefinable \else \ifx \reserved@a \@qrelax \@notdefinable \else #2\fi \fi }\@notdefinable 

$ texdef -t latex \@ifundefined

\@ifundefined:
macro:#1->\expandafter \ifx \csname #1\endcsname \relax \expandafter \@firstoftwo \else \expandafter \@secondoftwo \fi 

因此,显然,可以使用以下节从命令令牌中获取命令名称:

\edef\reserved@a{\expandafter\@gobble\string#1} 

...然后,可以在通过命令名称检查宏是否存在的宏中使用名称\reserved@a(不带反斜杠)。

使用这些定义,我整理了一个可重复使用的 newlength 命令的代码,名为\nnewlength

\documentclass{article}

\makeatletter
\def\nnewlength#1{%
  \edef\reserved@a{\expandafter\@gobble\string#1} %
  \@ifundefined\reserved@a{%
    \edef\reserved@b{\expandafter\@carcube\reserved@a xxx\@nil} %
    \ifx\reserved@b\@qend %
      \typeout{  -- Not definable (1, \reserved@a): #1} %\@notdefinable %
    \else %
      \ifx\reserved@a\@qrelax %
        \typeout{  -- Not definable (2, \reserved@a): #1} %\@notdefinable %
      \else %
        \typeout{  -- Making newskip: #1}
        \newskip#1%
      \fi %
    \fi %
  }%
  {\typeout{  -- Not definable (E, \reserved@a): #1}} %\@notdefinable%
}
\makeatother

\typeout{1st pass...}
\nnewlength{\mytmplen}
\typeout{2nd pass...}
\nnewlength{\mytmplen}

\begin{document}

\typeout{3rd pass...}
\nnewlength{\mytmplen}

\end{document}

输出为:

This is pdfTeX, Version 3.1415926-2.3-1.40.12 (TeX Live 2011)
...
1st pass...
 -- Making newskip: \mytmplen 
2nd pass...
 -- Not definable (E, mytmplen): \mytmplen 
(./test.aux)
3rd pass...
 -- Not definable (E, mytmplen): \mytmplen 
(./test.aux) )
No pages of output.
Transcript written on test.log.

相关内容