这是一个有点深奥的问题,但你必须相信我的话,这些玩具示例是从一些对我有用的东西中提取出来的。下面的代码解释了一切,但简要地说:
我有一个宏 ( \assignkeywords
),它将键/值对列表从一种格式转换为另一种格式,即 所需的格式\pgfkeys
。(我为什么要这样做,这不是重点。)然后,宏将此列表传递给作为其第二个参数提供的宏(\barr
在下面的示例中),后者又将列表传递给\pgfkeys
。这很有效。
但如果我尝试将“部分求值”版本传递给\barr
,\assignkeywords
例如\barr keythree=c
,则传递的附加键/值对\asignkeywords
不再被视为键/值对,而是(显然)被视为单个字符串。看来=
和在这种情况下不会以通常的方式,
解析。pgfkeys
梅威瑟:
\documentclass[11pt,letterpaper]{report}
\usepackage{pgffor}
\usepackage{pgfkeys}
\begin{document}
% The family of key/value pairs. Note that each key value gets stored in
% a macro with a matching name.
\pgfkeys{
/fake/.is family,
fake,
default/.style = {
keyone = x,
keytwo = y,
keythree = z,
},
keyone/.store in=\keyone,
keytwo/.store in=\keytwo,
keythree/.store in=\keythree,
}
% A macro for assembling a list of the form "keyone/a,keytwo/b"
% (argument 1) into the form "keyone=a,keytwo=b" and then
% passing it to the second argument.
\let\ea\expandafter
\newcommand{\assignkeywords}[2]{%
\def\keywordargslist{}%
\foreach \keyname/\keyvalue in {#1}{%
\ea\ea\ea\ea\ea\ea\ea\def%
\ea\ea\ea\ea\ea\ea\ea\temp%
\ea\ea\ea\ea\ea\ea\ea{%
\ea\ea\ea\keywordargslist%
\ea\keyname%
\ea=%
\keyvalue,}%
\global\let\keywordargslist\temp%
}%
% (((\keywordargslist)))
\ea#2\keywordargslist %
}
% A prototypical second argument for \assignkeywords. When
% passed a list like "keyone=a,keytwo=b" it passes these
% to \pgfkeys, thereby setting these keys (keyone, keytwo)
% to these values (a,b).
\def\barr#1 {%
\pgfkeys{fake, default, #1}%
\keyone, \keytwo, \keythree
}
\def\printkeys#1 {[[[#1]]]}
% A working example usage of \assignkeywords; produces a, b, z
\assignkeywords{keyone/a,keytwo/b}{\barr}
% A two-step working example usage of \assignkeywords; produces a, b, c
\def\foo#1 {\barr keythree=c,#1 }
\assignkeywords{keyone/a,keytwo/b}{\foo}
% A non-working example usage of \assignkeywords that seems like
% it ought to behave just like the previous example. Instead, pgfkeys
% throws
% I do not know the key '/fake/keyone=a,keytwo=b,'
% which seems to suggest that the "=" and "," are not getting parsed
% as such.
%%% \assignkeywords{keyone/a,keytwo/b}{\barr keythree=c,}
% If we just *print* the keys, they look right...
\assignkeywords{keyone/a,keytwo/b}{\printkeys keythree=c,}
% ...and if we print the keys in the second example, they look
% identical
\def\foo#1 {\printkeys keythree=c,#1 }
\assignkeywords{keyone/a,keytwo/b}{\foo}
\end{document}
答案1
问题很简单,你\ea#2\keywordsargslist
没有扩展\keywordsargslist
if#2
包含多个标记。TeX 看到的是:
\expandafter\barr keythree=c,\keywordsargslist
并将\expandafter
到达,它不会进一步扩展。因此,您的k
操作会将以下内容转发到:keythree=c
\barr
\pgfkeys
keythree=c,\keywordsargslist
\pgfkeys
然后将在第一个逗号处正确拆分并分配keythree
,但之后它将找不到顶级逗号,而是将其\keywordsargslist
视为单个键=值对。
\keywordsargslist
无论 的内容是什么,以下内容都会正确展开#2
。它还简化了使用\xdef
而不是一堆\expandafter
s 的宏创建。最后但并非最不重要的是,我将第一个更改\def\keywordsargslist{}
为\gdef
在保存堆栈上播放效果良好(如果您全局分配给变量,则始终全局分配给它,可提供更好的性能)。我没有更改空格分隔参数的可疑语法。
\documentclass[11pt,letterpaper]{report}
\usepackage{pgffor}
\usepackage{pgfkeys}
\begin{document}
% The family of key/value pairs. Note that each key value gets stored in
% a macro with a matching name.
\pgfkeys{
/fake/.is family,
fake,
default/.style = {
keyone = x,
keytwo = y,
keythree = z,
},
keyone/.store in=\keyone,
keytwo/.store in=\keytwo,
keythree/.store in=\keythree,
}
% A macro for assembling a list of the form "keyone/a,keytwo/b"
% (argument 1) into the form "keyone=a,keytwo=b" and then
% passing it to the second argument.
\newcommand{\assignkeywords}[2]{%
\gdef\keywordargslist{}%
\foreach \keyname/\keyvalue in {#1}{%
\xdef\keywordargslist
{%
\unexpanded\expandafter{\keywordargslist}%
\unexpanded\expandafter{\keyname}=%
{\unexpanded\expandafter{\keyvalue}},%
}%
}%
% (((\keywordargslist)))
\begingroup
\edef\tmp
{\endgroup\unexpanded{#2}\unexpanded\expandafter{\keywordargslist}}%
\tmp
}
% A prototypical second argument for \assignkeywords. When
% passed a list like "keyone=a,keytwo=b" it passes these
% to \pgfkeys, thereby setting these keys (keyone, keytwo)
% to these values (a,b).
\def\barr#1 {%
\pgfkeys{fake, default, #1}%
\keyone, \keytwo, \keythree
}
\def\printkeys#1 {[[[#1]]]}
% A working example usage of \assignkeywords; produces a, b, z
\assignkeywords{keyone/a,keytwo/b}{\barr}
% A two-step working example usage of \assignkeywords; produces a, b, c
\def\foo#1 {\barr keythree=c,#1 }
\assignkeywords{keyone/a,keytwo/b}{\foo}
% A non-working example usage of \assignkeywords that seems like
% it ought to behave just like the previous example. Instead, pgfkeys
% throws
% I do not know the key '/fake/keyone=a,keytwo=b,'
% which seems to suggest that the "=" and "," are not getting parsed
% as such.
\assignkeywords{keyone/a,keytwo/b}{\barr keythree=c,}
% If we just *print* the keys, they look right...
\assignkeywords{keyone/a,keytwo/b}{\printkeys keythree=c,}
% ...and if we print the keys in the second example, they look
% identical
\def\foo#1 {\printkeys keythree=c,#1 }
\assignkeywords{keyone/a,keytwo/b}{\foo}
\end{document}