我经常有单独的 .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}
答案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.