Quiero crear una base de datos que consta de bloques numerados de código TeX. En particular, quiero hacer algo como \mycommand{counterName}{Some text}
y guardar una nueva entrada en algún lugar, para usarla Some Text
más adelante en otra parte del documento. Hay CounterName
un contador al que puedo referirme para insertar el texto en el documento:
\newcounter{a}
\mycommand{a}{The first line}
\stepcounter{a}
\mycommand{a}{The second line}
.........
print{2}
Y TeX producirá "La segunda línea".
Estoy buscando algo parecido a glossaries
un paquete, pero con la capacidad de producir no todas las listas a la vez, sino una entrada específica para que parezca que el comando \print{n}
simplemente se sustituye por el texto en comando \mycommand{n}{TEXT}
.
Buscando en TeX.SX encontré algunas respuestas sobre datatool
paquetes y Lua
códigos, pero no encontré una solución que pueda aplicar.
Realmente agradecería una breve explicación sobre cómo usar datatool
, glossaries
o algo similar para estas cosas.
Respuesta1
Como mencionaste datatool
y glossaries
, aquí hay algunas alternativas.
Con datatool
, el método más simple requiere definir todas las entradas en orden incremental (sin usar un contador). El número de fila proporciona la indexación.
\documentclass{article}
\usepackage{datatool}
\DTLnewdb{data}
\newcommand{\addline}[1]{%
\DTLnewrow{data}%
\DTLnewdbentry{data}{Text}{#1}%
}
\newcommand{\print}[1]{%
\DTLgetvalue{\thisval}{data}{#1}{1}%
\thisval
}
\addline{The first line}
\addline{The second line}
\begin{document}
Line 2: \print{2}.
All lines:
\DTLforeach*{data}{\Text=Text}{\DTLcurrentindex. \Text.\par}
\end{document}
Esto produce:
Línea 2: La segunda línea.
Todas las líneas:
1. La primera línea.
2. La segunda línea.
Si desea definir sus entradas desordenadas usando un contador, puede hacerlo con una columna adicional:
\documentclass{article}
\usepackage{datatool}
\DTLnewdb{data}
\newcommand{\addline}[2]{%
\DTLnewrow{data}%
\dtlexpandnewvalue
\DTLnewdbentry{data}{Index}{\the\value{#1}}%
\dtlnoexpandnewvalue
\DTLnewdbentry{data}{Text}{#2}%
}
\newcommand{\print}[1]{%
\dtlgetrowindex{\thisrowidx}{data}{1}{#1}%
\ifx\thisrowidx\dtlnovalue
Not found!%
\else
\DTLgetvalue{\thisval}{data}{\thisrowidx}{2}%
\thisval
\fi
}
\newcounter{a}
\setcounter{a}{2}
\addline{a}{The second line}
\setcounter{a}{1}
\addline{a}{The first line}
\begin{document}
Line 2: \print{2}.
All lines:
\DTLforeach*{data}{\theIndex=Index,\Text=Text}{\theIndex. \Text.\par}
\end{document}
Esto produce:
Línea 2: La segunda línea.
Todas las líneas:
2. La segunda línea.
1. La primera línea.
La lista ahora está fuera de orden numérico, pero coincide con el orden en que se definieron los bloques. Puede ordenarlos antes de mostrar la lista:
\DTLsort{Index}{data}
\DTLforeach*{data}{\theIndex=Index,\Text=Text}{\theIndex. \Text.\par}
Línea 2: La segunda línea.
Todas las líneas:
1. La primera línea.
2. La segunda línea.
He aquí un glossaries
enfoque:
\documentclass{article}
\usepackage{glossaries-extra}
\glssetexpandfield{name}
\newcommand{\addline}[2]{%
\edef\thisidx{\the\value{#1}}%
\newglossaryentry{\thisidx}{name={\thisidx},description={#2}}%
}
\newcommand{\print}[1]{%
\glsentrydesc{#1}%
}
\newcounter{a}
\setcounter{a}{2}
\addline{a}{The second line}
\setcounter{a}{1}
\addline{a}{The first line}
\begin{document}
Line 2: \print{2}.
All lines:
\renewcommand{\glstreenamefmt}[1]{#1}
\renewcommand{\glossarysection}[2][]{}
\printunsrtglossary[style=index]
\end{document}
Esto produce:
Nuevamente esto enumera en orden de definición. Si desea ordenar la lista, puede utilizar lo siguiente:
\documentclass{article}
\usepackage[automake,nopostdot]{glossaries}
\makeglossaries
\glssetexpandfield{name}
\newcommand{\addline}[2]{%
\edef\thisidx{\the\value{#1}}%
\newglossaryentry{\thisidx}{name={\thisidx},description={#2}}%
}
\newcommand{\print}[1]{%
\glsentrydesc{#1}\glsadd{#1}%
}
\newcounter{a}
\setcounter{a}{2}
\addline{a}{The second line}
\setcounter{a}{1}
\addline{a}{The first line}
\begin{document}
Line 2: \print{2}.
All lines:
\renewcommand{\glstreenamefmt}[1]{#1}
\renewcommand{\glossarysection}[2][]{}
\printglossary[style=index,nonumberlist]
\end{document}
Esto produce:
Línea 2: La segunda línea.
Todas las líneas:
2 La segunda línea
Esto solo enumera la entrada que ha sido indexada (con \glsadd
). Si desea que se enumeren todas las entradas, utilice \glsaddall
(después de que se hayan definido todas las entradas).
\documentclass{article}
\usepackage[automake,nopostdot]{glossaries}
\makeglossaries
\glssetexpandfield{name}
\newcommand{\addline}[2]{%
\edef\thisidx{\the\value{#1}}%
\newglossaryentry{\thisidx}{name={\thisidx},description={#2}}%
}
\newcommand{\print}[1]{%
\glsentrydesc{#1}%
}
\newcounter{a}
\setcounter{a}{2}
\addline{a}{The second line}
\setcounter{a}{1}
\addline{a}{The first line}
\glsaddall
\begin{document}
Line 2: \print{2}.
All lines:
\renewcommand{\glstreenamefmt}[1]{#1}
\renewcommand{\glossarysection}[2][]{}
\printglossary[style=index,nonumberlist]
\end{document}
Esto produce:
Línea 2: La segunda línea.
Todas las líneas:
1 La primera línea
2 La segunda línea
Expansión
Es importante que el valor de indexación \the\value{#1}
se expanda completamente antes de almacenarlo; de lo contrario, seguirá cambiando a medida que el contador cambie de valor. Ambos datatool
y glossaries
tienen una forma de activar o desactivar la expansión al agregar/definir una nueva entrada.
En el caso de datatool
, la expansión se activa mediante \dtlexpandnewvalue
. En el caso de glossaries
, la expansión se activa para un campo particular usando\glssetexpandfield{
Etiqueta de campo}
.
El código que desea agregar (en el argumento final de \addline
) puede contener comandos frágiles, en cuyo caso es importante no expandir el valor. Con datatool
, la ampliación se vuelve a desactivar con \dtlnoexpandnewvalue
. Con glossaries
, el valor se almacena en la description
clave y la expansión está desactivada de forma predeterminada para ese campo.
Respuesta2
Lo siguiente se basa en el supuesto de que\printlistitem
ocurredespués \addlistitem
:
\documentclass{article}
\usepackage{xparse}
\newcounter{listitem}
\NewDocumentCommand{\addlistitem}{o m}{%
\IfValueTF{#1}
{\expandafter\def\csname #1-list\endcsname{#2}}
{\stepcounter{listitem}%
\begingroup\edef\x{\endgroup\noexpand\expandafter
\def\noexpand\csname \thelistitem-list\noexpand\endcsname}%
\x{#2}}%
}
\newcommand{\printlistitem}[1]{%
\ifcsname #1-list\endcsname
\csname #1-list\endcsname
\else
Item~#1 does not exist.
\fi
}
\begin{document}
\addlistitem{The first line}% 1
\addlistitem[B]{The second line}% C
\addlistitem{The third line}% 2
\printlistitem{2}
\printlistitem{1}
\printlistitem{3}
\printlistitem{B}
\end{document}
Se pueden agregar más modificaciones, incluida la verificación/manejo de errores y su modificación para manejar referencias inversas (usando una configuración \label
- ).\ref
Quizás le interese agregar un \printallitems
para enumerar todos los elementos que ha agregado en forma de ToC. El siguiente ejemplo lo imita estableciendo cada uno \addlistitem
como un archivo \section
. Puede realizar mejoras en la presentación según sea necesario:
\documentclass{article}
\usepackage{xparse,tocloft}
\newcounter{listitem}
\NewDocumentCommand{\addlistitem}{o m}{%
\IfValueTF{#1}
{\expandafter\def\csname #1-list\endcsname{#2}%
\addcontentsline{los}{listitem}{\protect\numberline{#1} #2}}
{\stepcounter{listitem}%
\begingroup\edef\x{\endgroup\noexpand\expandafter
\def\noexpand\csname \thelistitem-list\noexpand\endcsname}%
\x{#2}%
\addcontentsline{los}{listitem}{\protect\numberline{\thelistitem} #2}}%
}
\newcommand{\printlistitem}[1]{%
\ifcsname #1-list\endcsname
\csname #1-list\endcsname
\else
Item~#1 does not exist.
\fi
}
\makeatletter
\let\l@listitem\l@section
\newcommand{\printallitems}{{%
\renewcommand{\cftsecfont}{\mdseries}% Add more ToC-related tuning here
\@starttoc{los}}}
\makeatother
\begin{document}
\printallitems
\bigskip
\addlistitem{The first line}% 1
\addlistitem[B]{The second line}% C
\addlistitem{The third line}% 2
\printlistitem{2}
\printlistitem{1}
\printlistitem{3}
\printlistitem{B}
\end{document}