如何在 \ExplSyntaxOn 环境中使用冒号(':')作为 tikz 语法的一部分?

如何在 \ExplSyntaxOn 环境中使用冒号(':')作为 tikz 语法的一部分?

我想创建一个简单的 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 意识到这:是语法的一部分?

我努力了:

  1. :用替换\c_colon_str但结果相同。
  2. :用替换\char_generate:nn{58}{12},但这也无济于事。冒号 ( 1- 11, 13) 的其他任何 catcode 也无济于事。

答案1

你的两次尝试的问题在于,都没有扩展以生成实际的:12。这意味着 TiZ 看到了控制序列 \c_colon_str而不是它的扩展,:12

为了使这个工作,你需要扩展\c_colon_str(我忽略了这种\char_generate:nn方法,因为它会产生同样的东西,但需要付出更多的努力) \tikzset做它该做的事。通常有两种方法可以做你想做的事,但正如你在评论中所说,这两种方法都很冗长。


第一种是老办法。它由名称为\edef\x{<stuff-to-expand>}\x提供,其作用与名称所示一致:在参数中执行 -expansion ( ),然后使用它。这种方法有两个主要问题:1)expl3\use:xx\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

这种方法的优点是几乎不会遇到扩展问题。缺点是需要大量的样板代码来定义和使用临时宏,而且所有哈希值都必须翻倍。现在基本上就是一个选择问题了。


然而 TiZ 的设计不适合在异常的 catcode 机制下工作(例如expl3),因此我建议你让 TiZ 代码与代码分开expl3以避免此类问题。事实上,将 LaTeX3 代码与 LaTeX2e 代码连接起来是一个经常出现的问题,主要是由于不同的 catcode 设置。一种方法是将变量名称中的 替换_为,这样就变成了。事实上,这样做是为了在加载 LaTeX3 内核本身之前跟踪加载时选项。我对您的代码的建议:@\c_iskustvo_highlight_font_tl\c@iskustvo@highlight@font@tlexpl3.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⟩可以是local、global 或constant,⟨module⟩应该是您正在编写的包的前缀,或者是您的代码所特有的其他东西,⟨name⟩是变量的描述性名称,⟨type⟩是变量的类型。 在您的例子中,它是一个constant(因为您使用了\tl_const:Nn),您省略了模块名称,所以我使用了您的用户名,iskustvo,变量的名称是highlight_font,类型是token list 变量。 把它们放在一起,您就有了\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 更改它就可以工作。

相关内容