TikZ:pgfutil-common:pgfutil@in@ - 它是如何工作的?

TikZ:pgfutil-common:pgfutil@in@ - 它是如何工作的?

在为 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

相关内容