
Какой рекомендуемый способ определения переменной внутри документа и последующего извлечения ее значения?
Я гуглил несколько разных решений, обычно длиной около ~10 строк. Мне было интересно, должен ли быть более короткий способ сделать что-то вроде этого (Псевдокод):
\setvalue(VARIABLE1){foo foo bar}
и далее в документе
$\getvalue(VARIABLE1)$.
Я также видел решения, которые включают определение новой команды, но что, если эта команда уже используется внутри другого пакета? Это не похоже на независимое решение.
решение1
Ну, я знаю, что это не то, что вам нужно, но стандартный маршрут — либо с a, def
либо с a 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
без возникновения ошибки, то a renewcommand
можно использовать для изменения этой переменной позже.
решение2
Похоже, вы ищете систему ключ-значение. Могу ли я предложить pgfkeys
? Включая идею Янниса об использовании свойств для каждой переменной, я бы сделал это так:
\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}
(Они похожи на \@namedef
и \@nameuse
в LaTeX). Если вам нужны переменные, управляемые ключом-значением, вы можете использовать:
\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