我想要一个宏,\uniqueID{...}
如果在文档编译期间使用相同的参数调用该宏两次,它会在控制台中引发一条消息,或者更好的是,导致崩溃(控制台中出现一条消息)。
如何用 (La)TeX 制作这样的宏?
编辑
如果使用空参数调用该宏两次,则不会出现警告
答案1
对于每次调用\uniqueID{<id>}
,使用 存储一个控制序列<id>
。这样你就可以检查它是否<id>
已经存在并相应地生成错误:
\documentclass{article}
\makeatletter
\newcommand{\uniqueID}[1]{%
% First see if #1 is empty (https://tex.stackexchange.com/a/53091/5764)
\if\relax\detokenize{#1}\relax\else
\ifcsname ID-#1\endcsname % Check if ID already exists
\@latex@error{ID #1 already used}{}
\fi
\fi
\expandafter\def\csname ID-#1\endcsname{}% Create ID
#1% <process ID>
}
\makeatother
\begin{document}
\uniqueID{} % empty
\uniqueID{foo}
\uniqueID{} % empty
\uniqueID{bar}
\uniqueID{foo} % error
\end{document}
答案2
一种使用 的方法listofitems
。创建宏的参数的连接列表,然后搜索重复项。我提供详细输出(可以删除)来展示其工作原理。
\documentclass{article}
\usepackage{listofitems}
\def\usedIds{}
\makeatletter
\newcommand\uniqueId[1]{%
\g@addto@macro\usedIds{#1\endlinechar}%
\setsepchar{#1\endlinechar}%
\readlist\IDlist{\usedIds}%
\ifnum\listlen\IDlist[]>2\relax%
\typeout{BOOM! #1 is a duplicate.}BOOM! #1 is a duplicate.
\else
#1 OK.
\fi%
}
\makeatother
\begin{document}
\uniqueId{foo}
\uniqueId{foobar}
\uniqueId{foo}
\uniqueId{foobar}
\uniqueId{foobar}
\end{document}
这是一个非详细版本,它会输入到控制台然后触发错误。
\documentclass{article}
\usepackage{listofitems}
\def\usedIds{}
\makeatletter
\newcommand\uniqueId[1]{%
\g@addto@macro\usedIds{#1\endlinechar}%
\setsepchar{#1\endlinechar}%
\readlist\IDlist{\usedIds}%
\ifnum\listlen\IDlist[]>2\relax%
\typeout{BOOM! #1 is a duplicate.}
Abort \uniqueIdHasBeenTriggered
\fi%
}
\makeatother
\begin{document}
\uniqueId{foo}
\uniqueId{foobar}
\uniqueId{foo}
\uniqueId{foobar}
\uniqueId{foobar}
\end{document}
控制台是这样的:
This is pdfTeX, Version 3.14159265-2.6-1.40.18 (MiKTeX 2.9.6350)
entering extended mode
(C:/steven.segletes/TeX/Working/junk.tex
LaTeX2e <2017-04-15>
Babel <3.10> and hyphenation patterns for 72 language(s) loaded.
(C:\MikTeX\tex\latex\base\article.cls
Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
(C:\MikTeX\tex\latex\base\size10.clo))
(C:\MikTeX\tex\latex\listofitems\listofitems.sty
(C:\MikTeX\tex\generic\listofitems\listofitems.tex)) (junk.aux)
BOOM! foo is a duplicate.
! Undefined control sequence.
\uniqueId ...te.} Abort \uniqueIdHasBeenTriggered
\fi
l.20 \uniqueId{foo}
?
Process interrupted by user
答案3
这是一个expl3
实现:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\uniqueID}{m}
{
\tl_if_blank:nF { #1 }
{
\prop_if_in:NnTF \g_colas_uniqueid_prop { #1 }
{
\msg_error:nnn { colas } { uniqueID } { #1 }
}
{
\prop_gput:Nnn \g_colas_uniqueid_prop { #1 } { }
}
}
}
\prop_new:N \g_colas_uniqueid_prop
\msg_new:nnnn { colas } { uniqueID }
{
Already~used~ID~#1
}
{
The~ID~#1~has~already~been~used.~Too~bad.
}
\ExplSyntaxOff
\begin{document}
A \uniqueID{A}
Empty \uniqueID{}
Blank \uniqueID{ }
A \uniqueID{A}
Empty \uniqueID{}
\end{document}
当然你应该添加当ID为空或者新的时候执行的代码。
这是控制台输出:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! colas error: "uniqueID"
!
! Already used ID A
!
! See the colas documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l.36 A \uniqueID{A}
? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| The ID A has already been used. Too bad.
|...............................................
?