Quero criar um banco de dados que consiste em blocos numerados de código TeX. Em particular, quero fazer algo como \mycommand{counterName}{Some text}
e salvar uma nova entrada em algum lugar, para usá-la Some Text
posteriormente em outra parte do documento. É CounterName
um contador que posso consultar para inserir o texto no documento:
\newcounter{a}
\mycommand{a}{The first line}
\stepcounter{a}
\mycommand{a}{The second line}
.........
print{2}
E o TeX produzirá "A segunda linha".
Estou procurando algo como glossaries
pacote, mas com capacidade de produzir não todas as listas de uma vez, mas uma entrada específica para que pareça que o comando \print{n}
foi simplesmente substituído pelo texto em command \mycommand{n}{TEXT}
.
Pesquisando no TeX.SX encontrei algumas respostas sobre datatool
pacotes e Lua
códigos, mas não encontrei uma solução que pudesse aplicar.
Eu realmente apreciaria uma breve explicação sobre como usar datatool
ou glossaries
algo semelhante para essas coisas.
Responder1
Já que você mencionou datatool
e glossaries
, aqui estão algumas alternativas.
Com datatool
, o método mais simples requer a definição de todas as entradas em ordem incremental (sem usar um contador). O número da linha fornece a indexação.
\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}
Isso produz:
Linha 2: A segunda linha.
Todas as linhas:
1. A primeira linha.
2. A segunda linha.
Se você quiser definir suas entradas fora de ordem usando um contador, isso pode ser feito com uma coluna 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}
Isso produz:
Linha 2: A segunda linha.
Todas as linhas:
2. A segunda linha.
1. A primeira linha.
A lista agora está fora de ordem numérica, mas corresponde à ordem em que os blocos foram definidos. Você pode classificá-los antes de exibir a lista:
\DTLsort{Index}{data}
\DTLforeach*{data}{\theIndex=Index,\Text=Text}{\theIndex. \Text.\par}
Linha 2: A segunda linha.
Todas as linhas:
1. A primeira linha.
2. A segunda linha.
Aqui está uma glossaries
abordagem:
\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}
Isso produz:
Novamente, isso lista em ordem de definição. Se quiser que a lista seja classificada, você pode usar o seguinte:
\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}
Isso produz:
Linha 2: A segunda linha.
Todas as linhas:
2 A segunda linha
Isso lista apenas a entrada que foi indexada (com \glsadd
). Se você quiser que todas as entradas sejam listadas, use \glsaddall
(após todas as entradas terem sido definidas).
\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}
Isso produz:
Linha 2: A segunda linha.
Todas as linhas:
1 A primeira linha
2 A segunda linha
Expansão
É importante que o valor da indexação \the\value{#1}
seja totalmente expandido antes de ser armazenado, caso contrário ele continuará mudando conforme o contador muda de valor. Ambos datatool
têm glossaries
uma maneira de ativar ou desativar a expansão ao adicionar/definir uma nova entrada.
No caso de datatool
, a expansão é ativada usando \dtlexpandnewvalue
. No caso de glossaries
, a expansão é ativada para um campo específico usando\glssetexpandfield{
Legenda do campo}
.
O código que você deseja adicionar (no argumento final de \addline
) pode conter comandos frágeis; nesse caso, é importante não expandir o valor. Com datatool
, a expansão é desativada novamente usando \dtlnoexpandnewvalue
. Com glossaries
, o valor está sendo armazenado na description
chave e a expansão está desativada por padrão para esse campo.
Responder2
O seguinte é baseado na suposição que \printlistitem
ocorredepois \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}
Mais modificações podem ser adicionadas, incluindo verificação/tratamento de erros e modificação para lidar com referência reversa (usando uma configuração \label
- ).\ref
Você pode estar interessado em adicionar um \printallitems
para listar todos os itens adicionados na forma de um ToC. O exemplo a seguir imita isso definindo cada um \addlistitem
como um arquivo \section
. Você pode fazer ajustes na apresentação conforme necessário:
\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}