在列表中添加列表

在列表中添加列表

我已经进行了这样的设置:

%%% 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}

相关内容