
¿Cuál es la forma recomendada de definir una variable dentro de un documento y recuperar su valor más adelante?
Busqué en Google varias soluciones diferentes, generalmente de unas 10 líneas de largo. Me preguntaba si debe haber una forma más corta de hacer algo como esto (pseudocódigo):
\setvalue(VARIABLE1){foo foo bar}
y más adelante en el documento
$\getvalue(VARIABLE1)$.
También he visto soluciones que incluyen la definición de un nuevo comando, pero ¿qué pasa si ese comando ya se usa dentro de otro paquete? Realmente no parece una solución independiente.
Respuesta1
Bueno, sé que no es lo que quieres, pero la ruta estándar es con a def
o a newcommand
. El problema que has mencionado es el espacio de nombres global. Si lo usa, newcommand
le indicará si el comando ya está configurado (como un error en la compilación que indicará el newcommand
intento ofensivo), protegiéndolo de estos problemas.
% 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
Si pudiera anteponerlos a todos con su nombre o algún otro mnemotécnico, entonces es poco probable que haya conflictos. Este mnemónico luego se comporta como su propio (más o menos) espacio de nombres.
Suponiendo que la primera instancia de su variable está configurada con a newcommand
sin generar un error, entonces a renewcommand
se puede usar para modificar esa variable más adelante.
Respuesta2
Parece que estás buscando un sistema clave-valor. Puedo sugerir pgfkeys
? Incluyendo la idea de Yiannis de usar propiedades para cada variable, lo haría así:
\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}
Menos de diez líneas, incluso contando las que sólo tienen llaves. El funcionamiento es muy sencillo: pgfkeys
almacena variables como "archivos" en "directorios"; He decidido que el tuyo debería estar en el/variables
directorio, así quenoen el espacio de nombres global. (Por cierto, pgfkeys
las claves nunca entran en conflicto con los nombres de macros normales, por lo que su "espacio de nombres global" es diferente del espacio de nombres de las macros).
La \setvalue
macro simplemente cambia de directorio apropiadamente y luego llama a su tarea. La \getvalue
macro recupera la variable del directorio correcto.
El único truco es que en pgfkeys
, es necesario "conocer" una clave antes de asignarla; de lo contrario, debe llamarla como key/.initial = value
. Como no quiero obligarte a escribir eso, creé un "controlador" para variables desconocidas que simplemente agrega este fragmento de código detrás de escena.
Declaras una variable con propiedades usando \declare{variable/}
, y luego puedes usarla variable/property
como nombre de variable en \setvalue
(también puedes usarla variable/
como directorio predeterminado, así que escribe
\setvalue{variable, property 1 = value 1, property 2 = value 2}
lo cual es conveniente). La \declare
macro simplemente configura el controlador desconocido para el "directorio" /variables/variable/
(lo que significa que la línea críptica \declare{}
al principio configura el /variables/
directorio en sí).
Respuesta3
Prefiero definirlos usando una especie de método Lisp u orientado a objetos.
En el mínimo a continuación, utilizamos:
\setproperty{test}{aproperty}{12}
\getproperty{test}{aproperty}
Piense en ellos como representativos test.aproperty
(en realidad los definimos como test@paproperty
), de esta manera es muy poco probable que entren en conflicto con algún comando existente, excepto posiblemente el suyo:
Lo mínimo:
\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}
Respuesta4
Tu código es casi válido ConTeXt: defines una variable usando
\setvalue{variable1}{value}
y puede obtener su valor usando
\getvalue{variable1}
(Estos son similares a \@namedef
y \@nameuse
en LaTeX). Si desea variables basadas en valores clave, puede utilizar:
\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