在为 TikZ 编写小型库时,我尝试使用此宏来搜索@
。代码已编译,但结果是false
,尽管我确信它在测试字符串中。因此,我决定研究此宏的实现,但它通过自递归使用pgfutil@in@
和让我伤透了脑筋pgfutil@in@@
。有人可以解释一下它是如何工作的吗?此外,是否可以对其进行更改以使搜索@
适用?
% pgfutil@in@
\newif\ifpgfutil@in@
% Usage:
% \pgfutil@in@{one}{three two one}
% \ifpgfutil@in@
% -> will be true!
% \else
% \fi
%
% \pgfutil@in@{,}{1234,456567}
% \ifpgfutil@in@
% -> will be true!
% \else
% \fi
\def\pgfutil@in@#1#2{%
\def\pgfutil@in@@##1#1##2##3\pgfutil@in@@{%
\ifx\pgfutil@in@##2\pgfutil@in@false\else\pgfutil@in@true\fi}%
\pgfutil@in@@#2#1\pgfutil@in@\pgfutil@in@@}
我希望一定有某种方式可以通过catcode
...来调整它。
编辑:
使用示例:
\edef \pgf@marshal{\noexpand \pgfutil@in@{@}{\tikz@temp}}%
\pgf@marshal%
编辑2:
我发现使用\pgfutil@in@{@}{\tikz@temp}
带有设置的文档上下文\makeatletter
不会遇到任何问题,即使@
直接搜索也不会遇到任何问题。
在研究了 TikZ 如何包含库之后,我发现它保存了 的类别代码@
,将其设置为11
,包含库,然后恢复 的类别代码。因此,在名称中@
定义宏是可以的。@
但在执行之前\pgfutil@in@{@}{\tikz@temp}
(现在在我的库中的一些宏内)我会这样做:
\c@pgf@counta = \catcode`\@%
\showthe \c@pgf@counta%
并看到pdflatex
输出12
。嗯……我猜这是因为我的库中的宏只是被读取并保存以供以后使用。document
当的类别代码@
已经是时,它们是在环境内部执行的12
。我提出了这样的建议,我试图把\makeatletter
它放在前面\begin{document}
,它就像魔法一样有效!
那么,有没有办法以某种方式在执行时改变类别代码到@
它应该在的位置?11
另一个建议是,在读取宏时,类别代码为@
,11
但在执行时,的扩展值\tikz@temp
包含@
类别代码12
。因此,它们永远不会匹配,除非我\makeatletter
在文档上下文中执行此操作。
答案1
这些宏非常简单,使用标准的 TeX 参数分隔符。重复使用相同的宏名称会使代码不太清晰,但不会改变效果。为了方便起见,我们可以使用一些额外的标记来写出相同的概念:
\def\pgfutil@in@#1#2{%
\def\pgfutil@in@@##1#1##2##3\pgfutil@stop{%
\ifx\pgfutil@marker##2\pgfutil@in@false\else\pgfutil@in@true\fi
}%
\pgfutil@in@@#2#1\pgfutil@marker\pgfutil@stop
}
\def\pgfutil@marker{\pgfutil@marker}
然后,这个想法就是,辅助函数\pgfutil@in@@
被定义成它的参数必须包含,并且将被(在原文中)#1
停止。\pgfutil@stop
\pgfutil@in@@
\pgfutil@in@@
然后使用,以便总是后面至少跟着一个#1
,后面紧跟着一个标记(\pgfutil@in@
在原文中,\pgfutil@marker
在我的版本中)。如果#1
不在 中#2
,那么##1
将是#2
,##2
将是标记,并且##3
为空。\ifx
测试将为 TRUE,并且标志设置为 FALSE。另一方面,如果#1
是在#2
,那么将是第一个之前##1
的部分,将#2
#1
##2
不是是标记,##3
会进行整理。\ifx
将为 FALSE,因此标志将设置为 TRUE。
这一切都依赖于类别代码匹配#1
中的出现#2
。我们正在讨论@
,因此可以这样做
\makeatletter
\def\myfunction#1{%
\pgfutil@in@{@}{#1}%
...
}
\makeatother
并得到错误的结果。这是因为硬编码@
是“字母”,而任何 in 都#1
(可能)是“其他”。可以使用一些\lowercase
技巧来避免这种情况。
\makeatletter
\begingroup
\lccode`\*=`\@\relax
\lowercase{%
\endgroup
\def\myfunction#1{%
\pgfutil@in@{*}{#1}%
...
}
}
\makeatother
其思想是*
充当 的替代品@
:它的类别代码为“其他”,但被 变成@
了\lowercase
。
对于编辑后的问题,正确的方法是
\begingroup
\lccode`\*=`\@\relax
\lowercase{%
\endgroup
\edef\pgf@marshal{\noexpand\pgfutil@in@{*}{\tikz@temp}}%
}
\pgf@marshal