表的列类型可以用 定义和覆盖\newcolumntype
。我想知道是否已经定义了列类型,以便仅在定义了列类型的情况下执行示例。
编辑:与 egreg 的答案类似,我也创建了以下代码:
\newcommand\isColumntypeDefined[1]{%
\providebool{\tpl@coltype@#1}
\ifcsdef{NC@find@\string#1}{
\setboolean{\tpl@coltype@#1}{true}%
}{%
\setboolean{\tpl@coltype@#1}{false}
}%
\boolean{\tpl@coltype@#1}%
}
但由于没有创建有效命令,因此失败\tpl@coltype@#1
。此问题与latex @temps(wa) 命令。如果知道如何让这段代码可编译就太好了。
EDIT2:我将整个代码更改为 etoolbox 定义并最终以此结束
% Create list of predefined columntypes
\expandafter\let\csname columntype@l\endcsname\@empty
\expandafter\let\csname columntype@c\endcsname\@empty
\expandafter\let\csname columntype@r\endcsname\@empty
\expandafter\let\csname columntype@p\endcsname\@empty
\expandafter\let\csname columntype@m\endcsname\@empty
\expandafter\let\csname columntype@b\endcsname\@empty
\newcommand\CheckIfColumntypeDefined[1]{%
\providebool{tpl@coltype@#1}
\ifcsdef{NC@find@\string#1}%
{\setbool{tpl@coltype@#1}{true}}%
{\ifcsdef{columntype@\string#1}
{\setbool{tpl@coltype@#1}{true}}%
{\setbool{tpl@coltype@#1}{false}}%
}%
}
\newcommand\isColumntypeDefined[1]{tpl@coltype@#1}
\newcommand\IfColumntypeDefined[3]{%
\CheckIfColumntypeDefined{#1}
\ifboolexpr{ bool{\isColumntypeDefined{#1}} }{#2}{#3}%
}
答案1
指令
\newcolumntype{N}{...}
定义命令\NC@find@N
。你可以使用
\ifcsname NC@find@\string#1\endcsname
命令\safenewcolumntype
可以定义为
\makeatletter
\newcommand\@gobbleoptandone[2][]{}
\expandafter\let\csname safenct@l\endcsname\@empty
\expandafter\let\csname safenct@c\endcsname\@empty
\expandafter\let\csname safenct@r\endcsname\@empty
\expandafter\let\csname safenct@p\endcsname\@empty
\expandafter\let\csname safenct@m\endcsname\@empty
\expandafter\let\csname safenct@b\endcsname\@empty
\expandafter\let\csname safenct@@\endcsname\@empty
\expandafter\let\csname safenct@!\endcsname\@empty
\expandafter\let\csname safenct@|\endcsname\@empty
\expandafter\let\csname safenct@<\endcsname\@empty
\expandafter\let\csname safenct@>\endcsname\@empty
\expandafter\let\csname safenct@=\endcsname\@empty
\def\safenct@error#1{\PackageError{mypackage}
{Column type `\string#1' already defined}
{The column type you're trying to define is already\MessageBreak
existent; I'll ignore this new definition}}
\newcommand{\safenewcolumntype}[1]{%
\@tempswafalse
\ifcsname NC@find@\string#1\endcsname
\safenct@error{#1}\@tempswatrue
\fi
\ifcsname safenct@#1\endcsname
\safenct@error{#1}\@tempswatrue
\fi
\if@tempswa
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi{\@gobbleoptandone}{\newcolumntype{#1}}%
}
\makeatother
\@gobbleoptandone
如果列类型已经定义,我们将把吞噬可选参数和强制参数的命令放在其余标记列表之前:\safenewcolumntype{l}[1]{...}
将成为
\@gobbleoptandone[1]{...}
一切都很好。
否则我们将其放上去,\newcolumntype{#1}
这样它就能完成任务了。当然,最好还是修补一下原来的\newcolumntype
命令。
修补原始定义
\makeatletter
使用和之间的代码\makeatother
,我们重新定义了\newcolumntype
命令,以便检查列类型是否已定义,在前一种情况下,它不允许重新定义列类型。也可以定义命令\renewcolumntype
,但这似乎并不那么重要。
\documentclass{article}
\usepackage{array}
\makeatletter
\newcommand\@gobbleoptandone[2][]{}
\def\newcolumntype#1{%
\@tempswafalse
\edef\NC@char{\string#1}%
\@ifundefined{NC@find@\NC@char}%
{\@tfor\next:=<>clrmbp@!|\do
{\if\next\NC@char
\PackageError{safenct}{`\NC@char' is a primitive column type}
{You're trying to redefine a primitive column type;\MessageBreak
the redefinition will be ignored}%
\global\@safenct@deftrue
\fi}%
\if@tempswa\else\NC@list\expandafter{\the\NC@list\NC@do#1}\fi}%
{\PackageError{safenct}{Column `\NC@char' is already defined}
{This column type is already defined;\MessageBreak
the redefinition will be ignored}%
\@tempswatrue}%
\if@tempswa
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\@gobbleoptandone}
{\@namedef{NC@find@\NC@char}##1#1{\NC@{##1}}%
\@ifnextchar[{\newcol@{\NC@char}}{\newcol@{\NC@char}[0]}}
}
\makeatother
\newcolumntype{N}{>{Y}l<{Z}}
\newcolumntype{N}{r}
\newcolumntype{l}{r}
\begin{document}
\begin{tabular}{N}
xxxx\\
x\\
xx
\end{tabular}
\end{document}
当\newcolumntype{x}
扫描时,例程将暂存条件设置为 false,并检查是否x
属于原始列类型,如果是,则发出错误消息并将临时条件设置为 true。然后,它检查是否x
属于“派生”列类型,即通过\newcolumntype
自身定义。如果是,则再次将暂存条件设置为 false。最后,如之前提供的代码一样,采取正确的操作:如果条件为 false,则代码的以下部分将被\newcolumntype
吞噬,否则执行定义。