如果有一个简单的方法可以避免在以下代码片段中键入(或复制)字符串“nameofthenewcommand”,那就太好了
\newcommand{\nameofthenewcommand}{%
\node (nameofthenewcommand) [] {etc};
}
其目的是在代码其他地方的大型 tikzpicture 中使用。
有类似的东西就好了
\newcommand{\nameofthenewcommand}{%
\node (rocn) [] {etc};
}
其中 rocn 是我刚刚编写的字符串,tikz 应该将其识别为具有“命令名称的反射”含义,从而促使它用字符串“nameofthenewcommand”替换它。
为了实现这一目标您有何建议?
答案1
命令\nodestuff
宏为节点定义定义一个包装命令,并像宏一样命名节点。
\node
然而,在我看来,这可能无法捕获任何可能的调用,并且用途有限,因为之后仍然需要记住节点名称。
\documentclass{article}
\usepackage{tikz}
\newcommand{\nodestuff}[3][]{%
\expandafter\newcommand\csname #2\endcsname{%
\node[#1] (#2) #3;
}%
}
\begin{document}
\begin{tikzpicture}
\nodestuff[blue]{foo}{{$E=mc^{2}$}}
\nodestuff[blue]{foobar}{ at (3,4) {$E=(mc^{2})^{2} + (pc)^{2}$}}
\foo
\foobar
\draw (foo) -- (foobar) node[midway,right] {A};
\end{tikzpicture}
\end{document}
答案2
该\definenode
命令将节点名称作为参数,从而发出命令。参见示例;新命令将节点的坐标作为参数。
\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\ExplSyntaxOn
% syntactic sugar
\NewDocumentCommand{\newnamecommand}{m}
{
\exp_args:Nc \newcommand{#1}
}
\ExplSyntaxOff
\NewDocumentCommand{\definenode}{mom}{%
% #1 = command (no backslash)
% #2 (optional) = optional argument to \node
% #3 = replacement text
\IfNoValueTF{#2}
{\newnamecommand{#1}[1]{\node (#1) at ##1 {#3};}}
{\newnamecommand{#1}[1]{\node[#2] (#1) at ##1 {#3};}}%
}
% \foo will expand to "\node (foo) at #1 {$E=mc^2$};"
\definenode{foo}{$E=mc^2$}
% \baz will expand to "\node[blue] at #1 {Energy};"
\definenode{baz}[blue]{Energy}
\begin{document}
\begin{tikzpicture}
\foo{(0,0)}
\baz{(3,4)}
\draw (foo) -- (baz) node[midway,right] {A};
\end{tikzpicture}
\end{document}
答案3
如果您经常面临通过 创建控制序列标记的任务\csname..\endcsname
,则可以使用 TeX' #{
-表示法来定义一个宏\name
,其中第一个左括号之前的标记将作为参数,而嵌套在第一个左括号和相应的右括号中的标记将作为另一个/第二个参数,并且在 TeX 处理来自第一个参数的标记之前,从第二个参数形成控制序列标记。
我详细说明了\name
在线程中详细阐述了-macro定义控制序列,之后留有空格它于 2016 年 11 月 10 日在 TeX - LaTeX StackExchange 上启动。
\documentclass{article}
\usepackage{tikz}
\makeatletter
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
\newcommand\UD@innername[2]{%
\expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
\makeatother
\newcommand{\nodestuff}[3][]{%
\name\newcommand{#2}{%
\node[#1] (#2) #3;
}%
}
\begin{document}
\begin{tikzpicture}
\nodestuff[blue]{foonode}{{text at foonode}}
\nodestuff[blue]{barnode}{ at (2,3) {text at barnode}}
\foonode
\barnode
\draw (foonode) -- (barnode);
\end{tikzpicture}
\end{document}
如果您更喜欢采用另一种方式,即从控制序列标记中获取名称,您可以让 TeX 应用\string
并删除前面的转义字符(如果存在)。请注意一些极端情况,例如整数参数的值为\escapechar
32/表示空格。
此外,整数参数产生字符标记的可能值范围\escapechar
取决于引擎,即取决于使用的是 LuaTeX/XeTeX 还是“普通”TeX。
\documentclass{article}
\usepackage{tikz}
\usepackage{ifxetex, ifluatex}
\makeatletter
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\stringifysecond[2]{%
\expandafter\UD@PassFirstToSecond\expandafter{\romannumeral0\innerstringifysecond#2}{#1}%
}%
\newcommand\innerstringifysecond{%
\ifnum\escapechar=32 \expandafter\@gobble\else\expandafter\@firstofone\fi
% In case escapechar is 32, you get a space as escapechar, thus do nothing
% and have the space removed as terminator of the \romannumeral-expansion
% that currently is in progress.
{%
\ifnum\escapechar<0 \expandafter\@secondoftwo\else\expandafter\@firstofone\fi
{%
\ifnum\escapechar>\ifxetex 1114111 \else\ifluatex 1114111 \else 255 \fi\fi
\expandafter\@secondoftwo
\else
\expandafter\@firstoftwo
\fi
{%
% There is a non-space escapechar, thus gobble that escapechar
% as undelimited argument and insert space for terminating \romannumeral:
\@firstofone{\expandafter\expandafter\expandafter} \expandafter\@gobble
}%
}{%
% There is no escapechar, thus just insert space for terminating \romannumeral:
\@firstofone{\expandafter} %
}%
}%
\string
}%
%
\newcommand{\nodestuff}[2][]{%
\stringifysecond\innernodestuff{#2}{#1}{#2}%
}%
\newcommand\innernodestuff[4]{%
\newcommand#3{%
\node[#2] (#1) #4;
}%
}%
\makeatother
\begin{document}
\begin{tikzpicture}
\nodestuff[blue]{\foonode}{{text at foonode}}
\nodestuff[blue]{\barnode}{ at (2,3) {text at barnode}}
\foonode
\barnode
\draw (foonode) -- (barnode);
\end{tikzpicture}
\end{document}
我们看一下无名节点/无名宏的特殊情况:
对无名控制序列标记进行字符串化,该标记反过来可以作为表达式扩展的结果而产生\csname\endcsname
,或者可以由于在行尾标记反斜杠字符/类别代码为 0 的字符而产生,而整数参数的值为\endlinechar
负数或大于 255(普通 TeX 和 XeTeX;使用 LuaTeX 时尝试分配大于 127 的值以\endlinechar
产生错误消息并且不会执行)产生类别代码为 12(other) 的字符标记序列\csname\endcsname
。