我碰到 ”为变量赋值并检索以供日后使用的推荐方法是什么?“同时尝试弄清楚如何使用 PGFKEYS。但是,我在弄清楚如何让它检测未设置的键时遇到了麻烦。
梅威瑟:
\documentclass{minimal}
\usepackage{pgfkeys}
\newcommand{\setValue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getValue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
\pgfkeys{
/variables/#1.is family,
/variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
}%
}
\declare{}
\newcommand{\leftTailA}[1]{%
\declare{@mLT/}
\setValue{@mLT, Label = #1 }
\ifx\getValue{@mLT/Label}\empty
\else
$>$\getValue{@mLT/Label}$<$
\fi
}
\newcommand{\leftTailB}[1]{%
\ifx#1\empty
\else
$>$#1$<$
\fi
}
\pgfkeys{
/distMarkup/.is family, /distMarkup,
default/.style = { leftTailLabel = {} },
leftTailLabel/.estore in = \myLeftTailLabel,
}
\newcommand\distMarkup[1][]{% Note, don't put a space between the , and the #1, why? I don't know.
\pgfkeys{/distMarkup, default,#1}
\ifx\myLeftTailLabel\empty
\else
$>$\myLeftTailLabel$<$
\fi
}
\begin{document}
A: This has a label: \leftTailA{ label number 1 }
A: This has no label: \leftTailA{}
B: This has a label: \leftTailB{ label number 1 }
B: This has no label: \leftTailB{}
MA: This has a label: \distMarkup[leftTailLabel=label number 1]
MA: This has no label: \distMarkup[]
\end{document}
此代码示例的输出为:
答:这有一个标签:> 标签编号 1<
答:这个没有标签:><
B:这有一个标签:> 标签编号 1 <
B:这个没有标签:
MA:这有一个标签:>标签编号 1<
MA:这没有标签:
特别是,我不明白为什么“A:这没有标签”显示的是“><”而不是什么都没有。
额外积分: \declare 声明中的 ##1 起什么作用?
答案1
我发现您的代码的主要问题是 行\ifx\getValue{@mLT/Label}\empty
。 的行为\ifx
是比较紧随其后的两个标记\ifx
并检查它们是否相同。 在这种情况下,这两个标记是\getValue
和{
。 这两个标记永远不会相同,因此始终会采用错误分支。
解决方法是将\pgfkeysgetvalue
值存储到宏中,然后进行比较:
\newcommand{\leftTailA}[1]{%
\declare{@mLT/}%
\setValue{@mLT, Label = #1 }%
\pgfkeysgetvalue{@mLT/Label}{\temp}
\ifx\getValue\temp\empty
\else
$>$\getValue{@mLT/Label}$<$%
\fi
}
同样,中的比较\leftTailB
也是错误的。一种解决方法是将的参数存储\leftTailB
到宏中,然后将该宏与 进行比较,\empty
如下\ifx
所示:
\newcommand{\leftTailB}[1]{%
\def\temp{#1}%
\ifx\temp\empty
\else
$>$#1$<$%
\fi
}
如果要进行多次比较,可以定义一个名为的命令\ifempty
:
\makeatletter
\def\ifempty#1{%
\def\temp{#1}%
\ifx\temp\empty
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\def\ifpgfkeyempty#1{%
\pgfkeysgetvalue{#1}{\temp}%
\ifx\temp\empty
\expandafter\@firstoftwo
\else
\ifx\temp\relax
\expandafter\expandafter\expandafter\@firstoftwo
\else
\expandafter\expandafter\expandafter\@secondoftwo
\fi
\fi
}
\makeatother
in是未定义键的参数。您定义一个未定义键处理程序,它将任何未定义的键变成一个新键并存储传递给它##1
的\declare
值。如果您直接说:
/variables/.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = #1}
然后\pgfkeys{/variables/some new key=some value}
将其some new key
变成一个新变量 key 并存储some value
到其中。在宏内部,#1
指的是宏的第一个参数。 doubled##
用于转义#1
,以便它指的是未定义 key 的参数,而不是 的参数\declare
。
#1
为了表明和之间的关系##1
,请考虑以下代码:
\def\test#1{\def\testinner##1{(#1/##1)}}
\test{a} % This defines \testinner as #1->(a/#1)
\testinner{b} % expands to (a/b)
完整代码(顺便说一下,这仍然不是好的代码):
\documentclass{minimal}
\usepackage{etoolbox}
\usepackage{pgfkeys}
\newcommand{\setValue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getValue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
\pgfkeys{
/variables/#1.is family,
/variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
}%
}
\declare{}
\makeatletter
\def\ifempty#1{%
\def\temp{#1}%
\ifx\temp\empty
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\def\ifpgfkeyempty#1{%
\pgfkeysgetvalue{#1}{\temp}%
\ifx\temp\empty
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\makeatother
\newcommand{\leftTailA}[1]{%
\declare{@mLT/}%
\setValue{@mLT/Label = #1 }%
\ifpgfkeyempty{/variables/@mLT/Label}{}{%
$>$\getValue{@mLT/Label}$<$%
}
}
\newcommand{\leftTailB}[1]{%
\ifempty{#1}{}{%
$>$#1$<$%
}
}
\pgfkeys{
/distMarkup/.is family, /distMarkup,
default/.style = { leftTailLabel = {} },
leftTailLabel/.estore in = \myLeftTailLabel,
}
\newcommand\distMarkup[1][]{%
\pgfkeys{/distMarkup, default,#1}%
\ifx\myLeftTailLabel\empty
\else
$>$\myLeftTailLabel$<$%
\fi
}
\begin{document}
A: This has a label: \leftTailA{ label number 1 }
A: This has no label: \leftTailA{}
B: This has a label: \leftTailB{ label number 1 }
B: This has no label: \leftTailB{}
MA: This has a label: \distMarkup[leftTailLabel=label number 1]
MA: This has no label: \distMarkup[]
\end{document}
答案2
像这样吗?
\documentclass{article}
\usepackage{etoolbox}
\usepackage{pgfkeys}
\newcommand{\setValue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getValue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
\pgfkeys{
/variables/#1.is family,
/variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
}%
}
\declare{}
\newcommand{\leftTailA}[1]{%
\declare{@mLT/}%
\setValue{@mLT, Label = #1 }%
\edef\tmp{\getValue{@mLT/Label}}%
\ifx\tmp\empty
\else
$>$\getValue{@mLT/Label}$<$%
\fi
}
\newcommand{\leftTailB}[1]{%
\ifx#1\empty
\else
$>$#1$<$%
\fi
}
\pgfkeys{
/distMarkup/.is family, /distMarkup,
default/.style = { leftTailLabel = {} },
leftTailLabel/.estore in = \myLeftTailLabel,
}
\newcommand\distMarkup[1][]{% Note, don't put a space between the , and the #1, why? I don't know.
\pgfkeys{/distMarkup, default,#1}%
\ifx\myLeftTailLabel\empty
\else
$>$\myLeftTailLabel$<$%
\fi
}
\begin{document}
A: This has a label: \leftTailA{ label number 1 }
A: This has no label: \leftTailA{}
B: This has a label: \leftTailB{ label number 1 }
B: This has no label: \leftTailB{}
MA: This has a label: \distMarkup[leftTailLabel=label number 1]
MA: This has no label: \distMarkup[]
\end{document}
答案3
这是一个完全可扩展的解决方案。\pgfkeysvalueof
必须扩展三次才能获得键的实际值,所以我们需要 2*3+1 \expandafter
s。
\documentclass[varwidth]{standalone}
\usepackage{pgfkeys}
\makeatletter
\def\pgfkeys@firstoftwo#1#2{#1}
\def\pgfkeys@secondoftwo#1#2{#2}
\def\ifpgfkeysempty#1{%
\if\relax\detokenize\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{\pgfkeysvalueof{#1}}\relax
\expandafter\pgfkeys@firstoftwo
\else
\expandafter\pgfkeys@secondoftwo
\fi}
\def\pgfkeysmeaning#1{%
{\ttfamily #1->|\detokenize\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{\pgfkeysvalueof{#1}}|}}
\makeatother
\pgfkeys{%
/test1/.initial = {},
/test2/.initial = \relax,
/test3/.initial = {Foo},
/test4/.initial = {\def#1\bar{bar}},
}
\begin{document}
\begin{itemize}
\item \pgfkeysmeaning{/test1}
\ifpgfkeysempty{/test1}{Key is empty}{Key is not empty}
\item \pgfkeysmeaning{/test2}
\ifpgfkeysempty{/test2}{Key is empty}{Key is not empty}
\item \pgfkeysmeaning{/test3}
\ifpgfkeysempty{/test3}{Key is empty}{Key is not empty}
\item \pgfkeysmeaning{/test4}
\ifpgfkeysempty{/test4}{Key is empty}{Key is not empty}
\end{itemize}
\end{document}