pgfkeys 无法解析组合的键/值对字符串中的等号 (=) 或逗号 (,)

pgfkeys 无法解析组合的键/值对字符串中的等号 (=) 或逗号 (,)

这是一个有点深奥的问题,但你必须相信我的话,这些玩具示例是从一些对我有用的东西中提取出来的。下面的代码解释了一切,但简要地说:

我有一个宏 ( \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没有扩展\keywordsargslistif#2包含多个标记。TeX 看到的是:

\expandafter\barr keythree=c,\keywordsargslist

并将\expandafter到达,它不会进一步扩展。因此,您的k操作会将以下内容转发到:keythree=c\barr\pgfkeys

keythree=c,\keywordsargslist

\pgfkeys然后将在第一个逗号处正确拆分并分配keythree,但之后它将找不到顶级逗号,而是将其\keywordsargslist视为单个键=值对。

\keywordsargslist无论 的内容是什么,以下内容都会正确展开#2。它还简化了使用\xdef而不是一堆\expandafters 的宏创建。最后但并非最不重要的是,我将第一个更改\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}

相关内容