我正在尝试将堆栈数据结构与\newcounter{}
定义相结合,以便可以自动将分散在文本中的点集合配对在一起。
每个点要么被标记为,\openbracket
要么被标记为\closebracket
,并自动与一个相反定义的点配对以形成\openbracket
-\closebracket
对。闭对可以嵌套在其他闭括号对中,并且每对开/闭点分别用 tikz 节点\node(openX) {};
和标记\node(closeX) {};
[其中 X 是由外部计数器定义的整数]。
例如:
\openbraket First tier
\openbraket Second tier A
\openbraket Third tier
\closebracket
\closebracket
\openbracket Second tier B
\closebracket
\closebracket
应自动将上述\openbracket
\closebracket
点配对成 4 个闭合括号对;一个第一层括号,包含两个第二层括号,其中第一个 (A) 包含一个第三层括号。我的 MWE 还应从堆栈结构中弹出数据,以便上述示例中的 tikz 节点定义为:
(open0) First tier (open1) Second tier A (open2) Third tier
(close2) (close1) (open3) Second tier B (close3) (close0)
利用推送/弹出或者保存长度/尺寸?,在命令中保存计数器的当前值, 和将堆栈数据传递给 tikz 节点名称,我已经设法定义一个工作堆栈数据结构,并找到了一种将堆栈数据正确传递给我的\tikzmark
宏的方法。
但是,下面的 MWE 并未明确将 的当前值推送到bracketpairingcounter
上bracketpairingstack
,而是推送逐字命令字符串而不是所需的整数。因此,当每个\node(closeX) {};
tikz 标记从数据堆栈中弹出时,每个节点号都会在 的最后一个值处进行评估bracketpairingcounter
,而不是按顺序推送到堆栈上的不同整数。
我希望可以通过以某种方式强制我的 LaTeX 代码立即评估\openbracketname
下面的值来解决编号问题,但在这种情况下我无法获得\expandafter
或\edef{}
工作......
平均能量损失
\documentclass[openany]{article}
\usepackage{tikz}
%Define stack data structure commands (\push, \pop, \splitstack)
\newtoks\braketpairingstack
\braketpairingstack={\empty}
\def\push#1#2{%
\def\tmp{{#1}}%
\expandafter\expandafter\expandafter%
#2\expandafter\expandafter\expandafter{\expandafter\tmp\the#2}%
\ignorespaces}
\def\pop#1#2{%
\expandafter\splitstack\the#1\stop{#1}{#2}%
}
\def\splitstack#1#2\stop#3#4{%
\def\tmp{#1}
\ifx\tmp\empty
\else
\def#4{#1}\global#3={#2}%
\fi
}
%Define \tikzmark command
\def\tikzmark#1{%
\tikz[remember picture, overlay]\node[red](#1) {#1};%
}
%Define bracket pair counting commands (\openbracket, \closebracket)
\newcounter{bracketpairingcounter}
\newcommand{\openbraket}{%
\expandafter\edef\csname openbracketname\endcsname{\thebracketpairingcounter}%
\push{\openbracketname}{\braketpairingstack}%
\tikzmark{open\openbracketname}%
\stepcounter{bracketpairingcounter}%
}
\newcommand{\closebraket}{%
\pop{\braketpairingstack}{\closebracketname}%
\tikzmark{close\closebracketname}%
}
%Begin MWE document
\begin{document}
\openbraket Open first bracket.\\ %Correctly marked as open0
\openbraket Open second bracket.\\ %Correctly marked as open1
Close second bracket. \closebraket\\ %Correctly marked as close1
Close first bracket. \closebraket\\ %Incorrectly marked as close1
\end{document}
答案1
您想要这样做,但您也可以简化代码的其他部分\edef\temp{{#1}}
的定义。\push
\documentclass[openany]{article}
\usepackage{tikz}
%Define stack data structure commands (\push, \pop, \splitstack)
\newtoks\braketpairingstack
\braketpairingstack={\empty}
\def\push#1#2{%
\edef\tmp{{#1}\the#2}%
#2=\expandafter{\tmp}%
}
\def\pop#1#2{%
\expandafter\splitstack\the#1\stop{#1}{#2}%
}
\def\splitstack#1#2\stop#3#4{%
\def\tmp{#1}%
\ifx\tmp\empty
\else
\def#4{#1}\global#3={#2}%
\fi
}
%Define \tikzmark command
\def\tikzmark#1{%
\tikz[remember picture, overlay]\node[red](#1) {#1};%
}
%Define bracket pair counting commands (\openbracket, \closebracket)
\newcounter{bracketpairingcounter}
\newcommand{\openbraket}{%
\edef\openbracketname{\thebracketpairingcounter}%
\push{\openbracketname}{\braketpairingstack}%
\tikzmark{open\openbracketname}%
\stepcounter{bracketpairingcounter}%
}
\newcommand{\closebraket}{%
\pop{\braketpairingstack}{\closebracketname}%
\tikzmark{close\closebracketname}%
}
%Begin MWE document
\begin{document}
\openbraket Open first bracket. %Correctly marked as open0
\openbraket Open second bracket. %Correctly marked as open1
Close second bracket. \closebraket %Correctly marked as close1
Close first bracket. \closebraket %Correctly marked as close0
\end{document}
我们对\edef\tmp{{#1}\the#2}
进行完全扩展,#1
并添加标记寄存器 #2 的未扩展内容,因为在执行完传递寄存器内容的操作\the\tokenregister
后 不会继续扩展。然后我们设置 包含 的扩展(仅一层)。\the
#2
\tmp
请注意,这\ignorespaces
是不必要的,因为 的调用\push
会发现\tikzmark
;实际上它可能会导致不合时宜的扩展(在这种情况下不是)。