在文档内定义变量并稍后检索其值的推荐方法是什么?
我在 Google 上搜索了几种不同的解决方案,通常大约 10 行。我想知道,一定有一种更短的方法来做这样的事情(伪代码):
\setvalue(VARIABLE1){foo foo bar}
并在文档后面
$\getvalue(VARIABLE1)$.
我也见过一些解决方案,包括定义一个新命令,但如果该命令已经在另一个包中使用了怎么办?这似乎不是一个独立的解决方案。
答案1
好吧,我知道这不是你想要的,但标准路线是使用 或def
。newcommand
你接触到的问题是全局命名空间。如果你使用newcommand
它会告诉你命令是否已经设置(作为编译中的错误,将命名违规newcommand
尝试),保护你免受这些问题的影响。
% Set your new variable. In this case it will be
% called "\MyNewVariable" and the value will be "hello".
\newcommand{\MyNewVariable}{hello}
% Use to get the variable.
\MyNewVariable
如果您可以将自己的姓名或其他助记符添加到所有名称前面,则不太可能发生冲突。然后,此助记符将充当您自己的(某种)命名空间。
假设您的变量的第一个实例是用 a 设置的newcommand
而没有引发错误,那么 arenewcommand
可用于稍后更改该变量。
答案2
听起来您正在寻找一个键值系统。我可以建议吗pgfkeys
?包括 Yiannis 为每个变量使用属性的想法,我会这样做:
\documentclass{article}
\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{}
\begin{document}
\setvalue{VARIABLE1 = foo foo bar}
\getvalue{VARIABLE1}
\declare{test/}
\setvalue{test/property = 12}
\getvalue{test/property}
\end{document}
不到十行,即使算上只有括号的行。操作非常简单:pgfkeys
将变量作为“文件”存储在“目录”中;我决定你的变量应该在目录中/variables
,所以不是在全局命名空间中。(顺便说一句,pgfkeys
键永远不会与普通宏名称冲突,因此它的“全局命名空间”与宏命名空间不同。)
宏\setvalue
只是适当地更改目录,然后调用您的分配。宏\getvalue
从正确的目录中检索变量。
唯一的技巧是,在 中pgfkeys
,键需要在分配之前“已知”,否则您必须将其调用为key/.initial = value
。由于我不想强迫您编写它,因此我为未知变量创建了一个“处理程序”,只需在后台添加这一段代码即可。
您可以使用 声明一个具有属性的变量\declare{variable/}
,然后可以variable/property
在中用作变量名\setvalue
(您也可以用作variable/
默认目录,因此写
\setvalue{variable, property 1 = value 1, property 2 = value 2}
这很方便)。该\declare
宏只是为“目录”设置了未知的处理程序/variables/variable/
(这意味着\declare{}
开头的神秘行设置了/variables/
目录本身)。
答案3
我宁愿使用某种 Lisp 方式或面向对象的方式来定义它们。
在下面的最小示例中,我们使用:
\setproperty{test}{aproperty}{12}
\getproperty{test}{aproperty}
将它们视为代表test.aproperty
(我们实际上将它们定义为test@paproperty
),这样它就不太可能与任何现有命令发生冲突,除了您自己的命令:
最小的:
\documentclass{article}
\makeatletter
% Properties a la Lisp.
\def\ece#1#2{\expandafter#1\csname#2\endcsname}%
% \setproperty{ATOM}{PROPNAME}{VALUE} defines the property PROPNAME on the
% ``atom'' ATOM to have VALUE.
%
\def\setproperty#1#2#3{\ece\protected@edef{#1@p#2}{#3}}%
\def\setpropertyglobal#1#2#3{\ece\protected@xdef{#1@p#2}{#3}}%
%
%
% \getproperty{ATOM}{PROPNAME} expands to the value of the property
% PROPNAME on ATOM, or to nothing (i.e., \empty), if the property isn't
% present.
%
\def\getproperty#1#2{%
\expandafter\ifx\csname#1@p#2\endcsname\relax
% then \empty
\else \csname#1@p#2\endcsname
\fi
}%
%
\makeatother
\begin{document}
\setproperty{test}{aproperty}{12}
\getproperty{test}{aproperty}
\end{document}
答案4
您的代码几乎是有效的 ConTeXt:您使用定义一个变量
\setvalue{variable1}{value}
并可以使用获取其值
\getvalue{variable1}
(这些类似于LaTeX 中的\@namedef
和\@nameuse
)。如果您想要键值驱动的变量,您可以使用:
\definenamespace
[VAR]
[
name=VAR,
setup=list,
command=list,
parent=VAR,
]
\setupVAR
[a={default A},
b={default B}]
\defineVAR
[set1]
[a={set1 A},
c={set1 C}]
\defineVAR
[set2]
[b={set2 B},
c={set2 C}]
\starttext
\startlines
\namedVARparameter{set1}{a} % gives set1 A
\namedVARparameter{set1}{b} % gives default B
\namedVARparameter{set1}{c} % gives set1 C
\stoplines
\stoptext