
Quiero definir dinámicamente algunas macros que esencialmente crean una lista de \ref
s. Parece que puedo definir estas macros pero luego no puedo imprimirlas.
Aquí está mi M(no)NOSOTROS:
\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}
Quiero que la \Assigned{}
macro imprima los números de artículo "asignados" a esa persona. Es decir, después del itemise
entorno anterior debería obtener:
fred: 1,3
julie: 2,4,5
Desafortunadamente, me faltan los números de artículo y solo aparece:
fred:
julie:
El látex M(non)WE no tiene problemas pero, por razones que no entiendo, las \Assigned
macros no se expanden. He probado muchas variaciones usando \expandafter
1 o más veces, \edef
... pero nada parece funcionar.
En el archivo de registro, las \typeout{}
llamadas anteriores producen:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: `\DP@fred`
ASSIGNED: `\DP@julie`
Entonces parece que los \DP@#1
archivos están creados correctamente y son las \Assigned{}
macros las que no funcionan, lo que probablemente sea un problema de expansión. Usar \edef
no funciona... pero el hecho de que el problema de expansión ocurra DENTRO \typeout
me sugiere que estoy haciendo algo fundamentalmente incorrecto.
¿Alguien puede decirme cómo solucionar este problema?
Lo siguiente en mi lista de deseos sería imprimir "1,3-6,8" en lugar de "1,3,4,5,6,8", por ejemplo. ¡Pero primero lo primero!
Respuesta1
El entorno enumerate
agrega un grupo, por lo que los cambios \DP@#1
son locales y se pierden después de que se cierra el entorno. Así, el ejemplo hace que la definición sea 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
Actualización para compresión de rango
El ejemplo analiza la lista de comas \DP@#1
y define \Assign#1
con rangos comprimidos 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
Respuesta2
La sintaxis \def\Assigned#1{}
es incorrecta. La forma correcta es \expandafter\def\csname Assigned#1\endcsname{}
. Eso permite que su código se compile. Además, \edef
está localizado y no se puede acceder a él en un nivel superior. Cambiarlo para \xdef
solucionar eso.
\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}
El archivo de registro contiene:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: 1,3
ASSIGNED: 2,4,5
Respuesta3
\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}
Respuesta a la pregunta actualizada
Para obtener los nombres y los números de artículo:
\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}
Respuesta4
Quizás aprecies una versión 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}