
Quero definir dinamicamente algumas macros que essencialmente criam uma lista de \ref
s. Parece que consigo definir essas macros, mas não consigo imprimi-las.
Aqui está meu M(não)NÓS:
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\edef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{#1: \csname DP@#1\endcsname}
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
Quero que a \Assigned{}
macro imprima os números dos itens "atribuídos" a essa pessoa. Ou seja, após o itemise
ambiente acima eu deveria apenas obter:
fred: 1,3
julie: 2,4,5
Infelizmente, estou perdendo os números dos itens e só recebo:
fred:
julie:
O látex M(non)WE está sem problemas mas, por motivos que não entendo, as \Assigned
macros não estão se expandindo. Eu tentei muitas variações usando \expandafter
1 ou mais vezes, \edef
, ... mas nada parece funcionar.
No arquivo de log as \typeout{}
chamadas acima estão produzindo:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: `\DP@fred`
ASSIGNED: `\DP@julie`
Portanto, parece que os \DP@#1
bing foram criados corretamente e são as \Assigned{}
macros que não estão funcionando, o que provavelmente é um problema de expansão. Usar \edef
não funciona... mas o fato de o problema de expansão ocorrer DENTRO \typeout
sugere que estou fazendo algo fundamentalmente errado.
Alguém pode me dizer como consertar isso?
O próximo item da minha lista de desejos seria imprimir "1,3-6,8" em vez de "1,3,4,5,6,8", por exemplo. Mas primeiro as primeiras coisas!
Responder1
O ambiente enumerate
adiciona um grupo, portanto as alterações \DP@#1
são locais e perdidas após o fechamento do ambiente. Assim, o exemplo torna a definição global:
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname
\edef\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}%
\else
\edef\DP@tmp{\@currentlabel}%
\fi
\global\expandafter\let\csname DP@#1\endcsname\DP@tmp
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
% \expandafter\def\csname Assigned#1\endcsname{\csname DP@#1\endcsname}
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
Resultado:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: 1,3
ASSIGNED: 2,4,5
Atualização para compactação de intervalo
O exemplo analisa a lista de vírgulas \DP@#1
e define \Assign#1
intervalos compactados para entradas consecutivas:
\documentclass{article}
\usepackage{kvoptions}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname
\edef\DPx@tmp{\csname DP@#1\endcsname,\@currentlabel}%
\else
\edef\DPx@tmp{\@currentlabel}%
\fi
\global\expandafter\let\csname DP@#1\endcsname\DPx@tmp
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
\begingroup
\let\DPx@curr\@empty
\let\DPx@tmp\@empty
\expandafter\expandafter\expandafter\comma@parse
\expandafter\expandafter\expandafter{\csname DP@#1\endcsname}%
\AssignedAux
\ifx\DPx@curr\@empty
\else
\edef\DPx@tmp{\DPx@tmp-\DPx@curr}%
\fi
\global\expandafter\let\csname Assigned#1\endcsname\DPx@tmp
\endgroup
\typeout{ASSIGNED: \csname Assigned#1\endcsname}
}
\def\AssignedAux#1{%
\ifx\DPx@tmp\@empty
\def\DPx@tmp{#1}%
\count@=#1\relax
\else
\advance\count@\@ne
\ifnum#1=\count@
\def\DPx@curr{#1}%
\else
\count@=#1\relax
\ifx\DPx@curr\@empty
\edef\DPx@tmp{\DPx@tmp,#1}%
\else
\edef\DPx@tmp{\DPx@tmp-\DPx@curr,#1}%
\let\DPx@curr\@empty
\fi
\fi
\fi
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}\Assign{fred}
\item Strawberries \Assign{julie}
\item Pears \Assign{julie}
\item Lemons \Assign{fred}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
Resultado:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 1,3,4
ASSIGN: 2,4,5
ASSIGN: 2,4,5,6
ASSIGN: 1,3,4,7
ASSIGNED: 1,3-4,7
ASSIGNED: 2,4-6
Responder2
A sintaxe \def\Assigned#1{}
está incorreta. A maneira correta é \expandafter\def\csname Assigned#1\endcsname{}
. Isso permite que seu código seja compilado. Além disso, o \edef
está localizado e não pode ser acessado em um nível superior. Mudá-lo para \xdef
resolver isso.
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\xdef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{\expandafter\def\csname Assigned#1\endcsname{\csname DP@#1\endcsname}
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
O arquivo de log contém:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: 1,3
ASSIGNED: 2,4,5
Responder3
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\xdef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
\csname DP@#1\endcsname
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
Resposta à pergunta atualizada
Para obter os nomes, bem como os números dos itens:
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\xdef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
#1: \csname DP@#1\endcsname
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
Responder4
Você pode gostar de uma versão LaTeX3;
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\Assign}{m}
{
\andrew_assign:n { #1 }
}
\NewDocumentCommand{\Assigned}{m}
{
\andrew_assigned:n { #2 }
}
% syntactic sugar for shortening code
\cs_new:Npn \__andrew_seq:n #1
{
g_andrew_assignee_#1_seq
}
\cs_new_protected:Npn \andrew_assign:n #1
{% if the assignee is not yet defined, create a sequence
\seq_if_exist:cF { \__andrew_seq:n { #1 } }
{
\seq_new:c { \__andrew_seq:n { #1 } }
}
% globally add the item to the assignee's sequence
\seq_gput_right:cv { \__andrew_seq:n { #1 } } { @currentlabel }
}
\cs_new:Npn \andrew_assigned:n #1
{% print the assignee's items separated by a comma
\seq_use:cn { \__andrew_seq:n { #1 } } { ,~ }
}
\cs_generate_variant:Nn \seq_gput_right:Nn { cv }
\cs_generate_variant:Nn \seq_use:Nn { c }
\ExplSyntaxOff
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
Fred has \Assigned{fred} % should print 1,3
Julie has \Assigned{julie} % should print 2,4,5
\end{document}