我已经进行了这样的设置:
%%% some keys
\pgfkeys{/mystuff/first color/.code=\gdef\myfirstcolor{#1}}
\pgfkeys{/mystuff/first color/.default=black}
\pgfkeys{/mystuff/last color/.code=\gdef\mylastcolor{#1}}
\pgfkeys{/mystuff/last color/.default=black}
%%% main cmd
\newcommand{\mylist}[2][]{% aaa [opts] : bbb,...
\foreach \temp in {#2}{\expandafter\mysplit\temp\relax
first is \textcolor{\myfirstcolor}{\texttt{\myfirst}},
last is \textcolor{\mylastcolor}{\texttt{\mylast}} \par}
}
%%% helper cmds
\def\mysplit#1:#2\relax{%
\myfirstandopts#1[]\relax%
\gdef\mylast{#2}
}
\def\myfirstandopts#1[#2]#3\relax{%
\gdef\myfirst{#1}
\pgfkeys{/mystuff/.cd,first color,last color,#2}
}
我的想法是,我给出一个列表,并可以对每个项目应用一些键:
\mylist{Hello:World,
Hello[first color=blue]:World,
Hello[last color=red]:World}
如果我想提供多个选项,它不起作用:
\mylist{Hello [first color=blue,last color=red]:World}
! Paragraph ended before \mysplit was complete.
问题出在 foreach 中。它被传递:
Hello [first color=blue,last color=red]:World
这是 foreach 列表中的两个项目,第一个项目是
Hello [first color=blue
不同意该定义。
通过支撑密钥列表可以轻松解决这个问题:
\mylist{Hello[{first color=blue,last color=red}]:World}
但是,这并不那么直观,因为通常不需要用括号括住整个键列表。在这种情况下,这只是因为它在内部放在用逗号分隔的列表中。所以,我想自动添加括号。
我试图循环遍历键列表并[
用[{
和]
替换}]
。
为此我使用了以下宏:
\newcount\mycount
\def\mybracedkeys#1{\def\mybrcdkeys{}\myloop#1\relax}%% looping macro by David Carlisle
\def\myloop#1{%
\ifx\relax#1% check if \relax is reached, if so, do nothing
\else
\mycount`#1 % store the ascii code of the character in the counter
\ifnum\mycount=91% ascii code of [
\expandafter\def\expandafter\mybrcdkeys\expandafter{\mybrcdkeys [\bgroup}%
\else
\ifnum\mycount=93% ascii code of ]
\expandafter\def\expandafter\mybrcdkeys\expandafter{\mybrcdkeys \egroup]}%
\else
\expandafter\def\expandafter\mybrcdkeys\expandafter{\mybrcdkeys #1}
\fi
\fi
\expandafter\myloop\fi}
并重新定义\mylist
:
\renewcommand{\mylist}[2][]{% aaa [opts] : bbb,...
\mybracedkeys{#2}
\foreach \temp in \mybrcdkeys{\expandafter\mysplit\temp\relax
first is \textcolor{\myfirstcolor}{\texttt{\myfirst}},
last is \textcolor{\mylastcolor}{\texttt{\mylast}} \par}
}
这仍然不起作用并产生相同的错误,这并不是因为我们丢失了空格,因为同样的情况也会发生:
\pgfkeys{/mystuff/.cd,\bgroup first color=blue,last color=red\egroup}
我在此找到了@wipet 的解释回答:
{ 和 }(更准确地说是带有 catcode 1 和 2 的标记)在 TeX 中有四种不同的含义:
- 它们是宏定义的语法部分:
\def\foo...{...}
- 在 TeX 中作为单个标记列表扫描的每个标记序列(即在宏的参数中、在宏定义内......)都必须通过这些标记来平衡文本:
\macro{param{e}ter}.
- 它们是几个 TeX 原始构造的一部分,例如
\hbox...{...}, $e^{...}$, \write...{...}
。- 当它们在没有任何上述上下文的情况下使用时,它们会打开和关闭组。
和由
\bgroup
和\egroup
声明\let\bgroup={ \let\egroup=}
,您只能在上述第三和第四种含义中用和替换{
和。}
\bgroup
\egroup
我猜想在这种情况下我们处于第二种含义,因此无法做到这一点。
还有其他方法可以让它工作吗?最好不用expl3
。尽管经过这么多复杂情况(并且空格问题尚未解决),必须用括号括住键列表似乎并不那么糟糕。
完整代码:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\section*{Bracing a list within a list}
%%% some keys
\pgfkeys{/mystuff/first color/.code=\gdef\myfirstcolor{#1}}
\pgfkeys{/mystuff/first color/.default=black}
\pgfkeys{/mystuff/last color/.code=\gdef\mylastcolor{#1}}
\pgfkeys{/mystuff/last color/.default=black}
%%% main cmd
\newcommand{\mylist}[2][]{% aaa [opts] : bbb,...
\foreach \temp in {#2}{\expandafter\mysplit\temp\relax
first is \textcolor{\myfirstcolor}{\texttt{\myfirst}},
last is \textcolor{\mylastcolor}{\texttt{\mylast}} \par}
}
%%% helper cmds
\def\mysplit#1:#2\relax{%
\myfirstandopts#1[]\relax%
\gdef\mylast{#2}
}
\def\myfirstandopts#1[#2]#3\relax{%
\gdef\myfirst{#1}
\pgfkeys{/mystuff/.cd,first color,last color,#2}
}
\begin{verbatim}
\mylist{Hello:World,
Hello[first color=blue]:World,
Hello[last color=red]:World}
\end{verbatim}
\mylist{Hello:World,
Hello[first color=blue]:World,
Hello[last color=red]:World}
\begin{verbatim}
\mylist{Hello[{first color=blue,last color=red}]:World}
\end{verbatim}
\mylist{Hello[{first color=blue,last color=red}]:World}
\newcount\mycount
\def\mybracedkeys#1{\def\mybrcdkeys{}\myloop#1\relax}%% looping macro by David Carlisle
\def\myloop#1{%
\ifx\relax#1% check if \relax is reached, if so, do nothing
\else
\mycount`#1 % store the ascii code of the character in the counter
\ifnum\mycount=91% ascii code of [
\expandafter\def\expandafter\mybrcdkeys\expandafter{\mybrcdkeys [\bgroup}%
\else
\ifnum\mycount=93% ascii code of ]
\expandafter\def\expandafter\mybrcdkeys\expandafter{\mybrcdkeys \egroup]}%
\else
\expandafter\def\expandafter\mybrcdkeys\expandafter{\mybrcdkeys #1}
\fi
\fi
\expandafter\myloop\fi}
\renewcommand{\mylist}[2][]{% aaa [opts] : bbb,...
\mybracedkeys{#2}
\foreach \temp in \mybrcdkeys{\expandafter\mysplit\temp\relax
first is \textcolor{\myfirstcolor}{\texttt{\myfirst}},
last is \textcolor{\mylastcolor}{\texttt{\mylast}} \par}
}
does not work
\verb|\mylist{Hello[first color=blue,last color=red]:World}|
does not work
\verb|\pgfkeys{/mystuff/.cd,\bgroup first color=blue,last color=red\egroup}|
%https://tex.stackexchange.com/q/1930/53956
\end{document}
答案1
我的意思是你想用 保护括号[...]
,[{...}]
然后运行你的\foreach
。将你的\mylist
宏重命名为\mylistA
并定义
\def\mylist#1{%
\edef\tmp{\protectbk#1[\end]}%
\expandafter\mylistA\expandafter{\tmp}%
}
\def\protectbk#1[#2]{#1\ifx\end#2\else[{#2}]\expandafter\protectbk\fi}
现在,用法:
\mylist{Hello [first color=blue,last color=red]:World}
做
\mylistA{Hello [{first color=blue,last color=red}]:World}