我想检查某种颜色是否已经定义过,请考虑下面未执行的代码。
\documentclass{article}
\usepackage{xcolor}
\newcommand{\colorprovide}[2]{\ifx\undefined{#1}\colorlet{#1}{#2}\fi}
\begin{document}
%Initial Definition
\colorprovide{mycolor}{red}
\textcolor{mycolor}{Test 1}
%Will overwrite
\colorlet{mycolor}{green}
\textcolor{mycolor}{Test 2}
%Should NOT overwrite as it exists
\colorprovide{mycolor}{red}
\textcolor{mycolor}{Test 3}
\end{document}
换句话说,类似于\providecommand{...}
不更新现有命令(如果存在),我需要一个宏来不是如果颜色已经定义,则重新定义颜色。
\ifx\undefined...
由于逻辑检查部分不正确,上述代码会引发错误。
答案1
\definecolor{foo}{<model>}{<spec>}
或之后\colorlet{foo}{<color>}
,新的颜色规范存储在名为
\\color@foo
(名称中带有反斜杠)。你用
\documentclass{article}
\usepackage{xcolor}
\makeatletter
\newcommand{\colorprovide}[2]{%
\@ifundefined{\string\color@#1}{\colorlet{#1}{#2}}{}}
\makeatother
\begin{document}
%Initial Definition
\colorprovide{mycolor}{red}
\textcolor{mycolor}{Test 1}
%Will overwrite
\colorlet{mycolor}{blue}
\textcolor{mycolor}{Test 2}
%Should NOT overwrite as it exists
\colorprovide{mycolor}{red}
\textcolor{mycolor}{Test 3}
\end{document}
H. Oberdiek 建议的补充
实际上xcolor
已经定义了一个检查,但没有提供“公共版本”:
\def\@ifundefinedcolor#1{\@ifundefined{\string\color@#1}}
所以你可以说
\makeatletter
\newcommand{\colorprovide}[2]{%
\@ifundefinedcolor{#1}{\colorlet{#1}{#2}}{}}
\makeatother
这可能更清晰,并且不依赖于保存颜色规范的宏的内部实现。
答案2
这是一个老问题,但唯一的答案没有提到自 2.0 版(2004/07/04)以来\providecolor
可用的版本。xcolor
该命令有三个参数,在这种特殊情况下,可以将其用作\providecolor{<color to provide>}{named}{<existing color>}
。
\documentclass[varwidth,border=7pt]{standalone}
\usepackage{xcolor}
\newcommand{\colorprovide}[2]{\providecolor{#1}{named}{#2}}
\begin{document}
%Initial Definition
\colorprovide{mycolor}{red}
\textcolor{mycolor}{Test 1}
%Will overwrite
\colorlet{mycolor}{green}
\textcolor{mycolor}{Test 2}
%Should NOT overwrite as it exists
\colorprovide{mycolor}{red}
\textcolor{mycolor}{Test 3}
\end{document}