我想创建一个简单的 tikz 样式highlight
,它将在对象周围绘制椭圆并在请求的位置写入标签。为了避免通过文本参数提供字体,我将其直接放在 tikz 样式中。
以下是 MWE:
\documentclass {article}
\RequirePackage [utf8] {inputenc}
\RequirePackage {tikz}
\RequirePackage {xparse}
\usetikzlibrary {fit}
\usetikzlibrary {shapes}
\ExplSyntaxOn
\tl_const:Nn \c_highlight_font {\fontsize {20} {24} \selectfont \bfseries}
% #1 Angle
% #2 Relative position
% #3 Text
\tikzset
{
highlight/.style~n~args = 3
{
ellipse,
inner~sep = 0mm,
draw = blue,
dashed,
very~thick,
label={[#2, blue]#1:\c_highlight_font #3}
}
}
\ExplSyntaxOff
\begin {document}
\ExplSyntaxOn
\begin{tikzpicture}
\node (node_to_highlight) [minimum~size = 1cm, draw] at (0, 0) {};
\node (highlight) [highlight = {210}{below~left}{1}, fit = (node_to_highlight)] {};
\end{tikzpicture}
\ExplSyntaxOff
\end {document}
此代码存在问题。定义中的
冒号 ( :
)label
已更改 catcode,因为它位于环境内\ExplSyntaxOn
,因此被视为字母,而不是tikz
语法的一部分。
这最终会写210:1
为标签,而不是1
角度210
。
我知道一个显而易见的解决方法:在环境
之外定义 tikz 样式,并用可以在环境之外工作的东西来改变,因为它的名称 没有问题。\ExplSyntaxOn
\c_highlight_font
\def\highlightFont
\ExplSyntaxOn
_
如果可能的话,我宁愿保留 LaTeX3 变量。
有没有办法添加一些“转义序列”或类似的东西,让 tikz 意识到这:
是语法的一部分?
我努力了:
:
用替换\c_colon_str
但结果相同。:
用替换\char_generate:nn{58}{12}
,但这也无济于事。冒号 (1
-11
,13
) 的其他任何 catcode 也无济于事。
答案1
你的两次尝试的问题在于,都没有扩展以生成实际的:
12。这意味着 Ti钾Z 看到了控制序列 \c_colon_str
而不是它的扩展,:
12。
为了使这个工作,你需要扩展\c_colon_str
(我忽略了这种\char_generate:nn
方法,因为它会产生同样的东西,但需要付出更多的努力)前 \tikzset
做它该做的事。通常有两种方法可以做你想做的事,但正如你在评论中所说,这两种方法都很冗长。
第一种是老办法。它由名称为\edef\x{<stuff-to-expand>}\x
提供,其作用与名称所示一致:在参数中执行 -expansion ( ),然后使用它。这种方法有两个主要问题:1)expl3
\use:x
x
\edef
一切被扩展,并且 2) 参数标记 ( #
) 需要加倍。 在您的例子中,label
将从(为简洁起见简化)变为:
\tikzset{label={[ #2,blue] #1\c_colon_str \c_iskustvo_highlight_font_tl #3}}
到
\use:x{\exp_not:N\tikzset{label={[##2,blue]##1\c_colon_str\exp_not:N\c_iskustvo_highlight_font_tl##3}}}
注意在每个控制序列前添加\exp_not:N
(每个活动字符也应该被\exp_not:N
'ed ),并且 加倍#
。您可以通过将其他所有内容包装在\exp_not:n
(不是N
)中来避免哈希值加倍:
\use:x{\exp_not:N\tikzset{label={\exp_not:n{[#2,blue]#1}\c_colon_str\exp_not:n{\c_iskustvo_highlight_font_tl#3}}}}
这并不完全短。为了避免哈希值加倍,您可以使用e
-type 扩展而不是x
,但这样做并没有太多好处。 -typee
是 e-TeX 原语\expanded
(在 TeXLive 2019 的 pdfTeX 和 XeTeX 中引入,LuaTeX 更早引入),或者在较旧的发行版中,是它的模拟expl3
(这会使其速度慢得多)。
另一种方法是定义一个宏,将要替换的标记作为参数。基本思想是执行\def\__temp:w#1{<stuff with #1>}
和\exp_args:No\__temp:w{\c_colon_str}
,然后将的扩展\c_colon_str
插入到适当的位置。在您的例子中,将从label
(为清晰起见添加了空格)变为:
\tikzset { label = {[##2, blue]##1 \c_colon_str \c_iskustvo_highlight_font_tl ##3} }
到:
\cs_set_protected:Npn \__iskustvo_tmp:w #1
{ \tikzset { label = {[##2, blue]##1 #1 \c_iskustvo_highlight_font_tl ##3} } }
\exp_args:NV \__iskustvo_tmp:w \c_colon_str
这种方法的优点是几乎不会遇到扩展问题。缺点是需要大量的样板代码来定义和使用临时宏,而且所有哈希值都必须翻倍。现在基本上就是一个选择问题了。
然而 Ti钾Z 的设计不适合在异常的 catcode 机制下工作(例如expl3
),因此我建议你让 Ti钾Z 代码与代码分开expl3
以避免此类问题。事实上,将 LaTeX3 代码与 LaTeX2e 代码连接起来是一个经常出现的问题,主要是由于不同的 catcode 设置。一种方法是将变量名称中的 替换_
为,这样就变成了。事实上,这样做是为了在加载 LaTeX3 内核本身之前跟踪加载时选项。我对您的代码的建议:@
\c_iskustvo_highlight_font_tl
\c@iskustvo@highlight@font@tl
expl3.sty
\documentclass{article}
\RequirePackage[utf8]{inputenc}
\RequirePackage{tikz}
\RequirePackage{xparse}
\usetikzlibrary{fit}
\usetikzlibrary{shapes}
\makeatletter
\ExplSyntaxOn
\tl_const:Nn \c@iskustvo@highlight@font@tl {\fontsize {20} {24} \selectfont \bfseries}
\ExplSyntaxOff
% #1 Angle
% #2 Relative position
% #3 Text
\tikzset
{
highlight/.style n args = 3%<--
{
ellipse,
inner sep = 0mm,
draw = blue,
dashed,
very thick,
label = {[#2, blue]#1:\c@iskustvo@highlight@font@tl #3}
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node (node_to_highlight) [minimum size = 1cm, draw] at (0, 0) {};
\node (highlight) [highlight = {210}{below left}{1}, fit = (node_to_highlight)] {};
\end{tikzpicture}
\end{document}
附注:变量命名的惯例是\⟨scope⟩_⟨module⟩_⟨name⟩_⟨type⟩
。⟨scope⟩
可以是l
ocal、g
lobal 或c
onstant,⟨module⟩
应该是您正在编写的包的前缀,或者是您的代码所特有的其他东西,⟨name⟩
是变量的描述性名称,⟨type⟩
是变量的类型。 在您的例子中,它是一个c
onstant(因为您使用了\tl_const:Nn
),您省略了模块名称,所以我使用了您的用户名,iskustvo
,变量的名称是highlight_font
,类型是t
oken l
ist 变量。 把它们放在一起,您就有了\c_iskustvo_highlight_font_tl
。
答案2
你可以使用我的包...
\documentclass {article}
\usepackage{precattl} % ======== change 1, add the package here
\RequirePackage [utf8] {inputenc} % side note, see [macros - What's the difference between \RequirePackage and \usepackage? - TeX - LaTeX Stack Exchange](https://tex.stackexchange.com/questions/19919/whats-the-difference-between-requirepackage-and-usepackage)
\RequirePackage {tikz}
\RequirePackage {xparse}
\usetikzlibrary {fit}
\usetikzlibrary {shapes}
\ExplSyntaxOn
\tl_const:Nn \c_highlight_font {\fontsize {20} {24} \selectfont \bfseries}
\precattl_exec:n {
% #1 Angle
% #2 Relative position
% #3 Text
\tikzset
{
highlight/.style~n~args = 3
{
ellipse,
inner~sep = 0mm,
draw = blue,
dashed,
very~thick,
label={[#2, blue]#1 \cO\: \c_highlight_font #3}
% ======== change 2 ^^^^^ specify you want the colon in other catcode
}
}
}
\ExplSyntaxOff
\begin {document}
\ExplSyntaxOn
\begin{tikzpicture}
\node (node_to_highlight) [minimum~size = 1cm, draw] at (0, 0) {};
\node (highlight) [highlight = {210}{below~left}{1}, fit = (node_to_highlight)] {};
\end{tikzpicture}
\ExplSyntaxOff
\end {document}
不是针对这种情况的,但基本上它允许在令牌列表中指定任意 catcode,只要代码本身中没有 catcode 更改它就可以工作。