在接受的答案中\begin{environment} 和 \end{environment} 之间的代码存储在数组中它展示了如何使用语法创建自动定理列表expl3
。但是,该\printtheorems
命令仅在定理之后调用时才有效。
有没有办法在定理之前调用它?我在想一个可能的方法是编译 .tex 两次,第一次是为了得到定理,第二次是为了显示它们(就像目录对章节、部分等所做的那样)。
上面链接的代码和相应的输出是:
\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{environ}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newtheoremx}{momo}
{
% * Let's duplicate the working of \newtheorem; \newtheoremx should
% be used for theorems that need to be listed
% * \newtheoremx{theorem}{Theorem} will actually do
% \newtheorem{theorem@inner}{Theorem} (honoring the usual optional arguments)
% * We also need a property list to store along with the theorem
% the one which it is subordinate to
\IfValueTF{#2}
{
\newtheorem{#1@inner}[#2@inner]{#3}
% #1 is subordinate to #2
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #2 }
}
{
\IfValueTF{#4}
{
\newtheorem{#1@inner}{#3}[#4]
}
{
\newtheorem{#1@inner}{#3}
}
% #1 is not subordinate, store the name itself
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #1 }
}
% define a "grabbing" environment #1 with the usual features
\NewEnviron{#1}[1][]
{
% start the inner environment (without or with optional argument)
\tl_if_empty:nTF { ##1 }
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% save the statement number
\tl_gset:Nx \g__riccardo_theorems_number_tl { \use:c {@currentlabel} }
% typeset the statement
\BODY
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
{ #1 } % name
{ \g__riccardo_theorems_number_tl } % number
{ \exp_not:n { ##1 } } % attribution
{ \exp_not:V \BODY } } % body
}
}
% allocate the needed variables
\prop_new:N \g_riccardo_theorems_prop
\seq_new:N \g_riccardo_theorems_seq
\tl_new:N \g__riccardo_theorems_number_tl
% print the stored theorems
\NewDocumentCommand{\printtheorems}{}
{
% we need a group where nullifying the action of \label
\group_begin:
\cs_set_eq:NN \label \use_none:n
% map the sequence, passing each item to the function that prints a theorem
\seq_map_function:NN \g_riccardo_theorems_seq \riccardo_printtheorems:n
% end the group
\group_end:
}
\cs_new_protected:Nn \riccardo_printtheorems:n
{
% just pass the argument in the form {name}{number}{attribution}{text}
% to a four argument function
\__riccardo_printtheorems:nnnn #1
}
\cs_new_protected:Nn \__riccardo_printtheorems:nnnn
{
% redefine \the<statement>@inner to yield the stored number
% we use the property list to use the correct counter
% (for instance, in case of "lemma", <statement> will be "theorem"
\cs_set:cpn { the \prop_item:Nn \g_riccardo_theorems_prop {#1} @inner } { #2 }
\tl_if_empty:nTF { #3 }
{
% no attribution
\begin{#1@inner} #4 \end{#1@inner}
}
{
% attribution
\begin{#1@inner}[#3] #4 \end{#1@inner}
}
}
\ExplSyntaxOff
\newtheoremx{theorem}{Theorem}[section]
\newtheoremx{lemma}[theorem]{Lemma}
\begin{document}
\section{First test}
\begin{theorem}[Important]\label{thm:important}
This is a theorem about $\log_a x$.
\end{theorem}
\begin{lemma}\label{lem:whatever}
This is a lemma.
\end{lemma}
\begin{theorem}\label{thm:unimportant}
This is another theorem
\end{theorem}
\section{Second test}
\begin{theorem}\label{thm:soandso}
Again a theorem.
\end{theorem}
\section{Theorems}
\printtheorems
\end{document}
编辑:MWE 显示问题
\documentclass{memoir}
\usepackage{amsmath, amsthm, hyperref, environ, xparse, showkeys}
\ExplSyntaxOn
\NewDocumentCommand{\newtheoremx}{momo}
{
% * Let's duplicate the working of \newtheorem; \newtheoremx should
% be used for theorems that need to be listed
% * \newtheoremx{theorem}{Theorem} will actually do
% \newtheorem{theorem@inner}{Theorem} (honoring the usual optional arguments)
% * We also need a property list to store along with the theorem
% the one which it is subordinate to
\IfValueTF{#2}
{
\newtheorem{#1@inner}[#2@inner]{#3}
% #1 is subordinate to #2
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #2 }
}
{
\IfValueTF{#4}
{
\newtheorem{#1@inner}{#3}[#4]
}
{
\newtheorem{#1@inner}{#3}
}
% #1 is not subordinate, store the name itself
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #1 }
\seq_gput_right:Nn \g_riccardo_theorems_counters_seq { #1 }
}
% define a "grabbing" environment #1 with the usual features
\NewEnviron{#1}[1][]
{
% start the inner environment (without or with optional argument)
\tl_if_empty:nTF { ##1 }
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% save the statement number
\tl_gset:Nx \g__riccardo_theorems_number_tl { \use:c {@currentlabel} }
% typeset the statement
\BODY
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
{ #1 } % name
{ \g__riccardo_theorems_number_tl } % number
{ \exp_not:n { ##1 } } % attribution
{ \exp_not:V \BODY } }% body
}
}
% allocate the needed variables
\prop_new:N \g_riccardo_theorems_prop
\seq_new:N \g_riccardo_theorems_seq
\tl_new:N \g__riccardo_theorems_number_tl
\iow_new:N \g_riccardo_theorems_stream
\seq_new:N \g_riccardo_theorems_counters_seq
% print the stored theorems
\NewDocumentCommand{\printtheorems}{}
{
% we need a group where nullifying the action of \label
\group_begin:
\cs_set_eq:NN \label \use_none:n
% map the sequence, passing each item to the function that prints a theorem
\file_if_exist_input:n { \c_sys_jobname_str.thl }
% end the group
\group_end:
\seq_map_inline:Nn \g_riccardo_theorems_counters_seq
{
\setcounter{##1@inner}{0}
}
}
\cs_new_protected:Nn \riccardo_theorems_save:
{
\seq_map_function:NN \g_riccardo_theorems_seq \__riccardo_theorems_save:n
}
\cs_new_protected:Nn \__riccardo_theorems_save:n
{
\iow_now:Nn \g_riccardo_theorems_stream
{
\savedtheorem #1
}
}
\AtEndDocument
{
\iow_open:Nn \g_riccardo_theorems_stream { \c_sys_jobname_str.thl }
\riccardo_theorems_save:
\iow_close:N \g_riccardo_theorems_stream
}
\NewDocumentCommand{\savedtheorem}{mmmm}
{
% redefine \the<statement>@inner to yield the stored number
% we use the property list to use the correct counter
% (for instance, in case of "lemma", <statement> will be "theorem"
\cs_set:cpn { the \prop_item:Nn \g_riccardo_theorems_prop {#1} @inner } { #2 }
\tl_if_empty:nTF { #3 }
{
% no attribution
\begin{#1@inner} #4 \end{#1@inner}
}
{
% attribution
\begin{#1@inner}[#3] #4 \end{#1@inner}
}
}
\ExplSyntaxOff
\newtheoremx{theorem}{Theorem}[chapter]
\newtheoremx{lemma}[theorem]{Lemma}
\begin{document}
\chapter{Theorems}
\printtheorems
\clearpage
\section{First theorem}
\begin{theorem}[Important] \label{thm_1}
This is a theorem about $\log_a x$.
\end{theorem}
\clearpage
This is a link to \hyperref[thm_1]{Theorem 1}.
\end{document}
答案1
定理可以像以前一样按顺序保存;在文档末尾,它们可以写入辅助文件并\printtheorems
输入(如果存在)。
\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{xparse,environ}
\ExplSyntaxOn
\NewDocumentCommand{\newtheoremx}{smomo}
{
\IfBooleanTF{#1}
{
\printthm_nonumber:nn { #2 } { #4 }
}
{
\printthm_number:nnnn { #2 } { #3 } { #4 } { #5 }
}
}
\cs_new_protected:Nn \printthm_nonumber:nn
{
\newtheorem*{#1@inner}{#2}
\NewEnviron{#1}[1][]
{
% start the inner environment (without or with optional argument)
\tl_if_empty:nTF { ##1 }
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% typeset the statement
\BODY
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
*
{ #1 } % name
{ } % number
\tl_if_novalue:nF { ##1 } { [\exp_not:n { ##1 }] } % attribution
{ \exp_not:V \BODY } % body
}
}
}
\cs_new_protected:Nn \printthm_number:nnnn
{
% * Let's duplicate the working of \newtheorem; \newtheoremx should
% be used for theorems that need to be listed
% * \newtheoremx{theorem}{Theorem} will actually do
% \newtheorem{theorem@inner}{Theorem} (honoring the usual optional arguments)
% * We also need a property list to store along with the theorem
% the one which it is subordinate to
\tl_if_novalue:nTF { #2 }
{
\tl_if_novalue:nTF { #4 }
{
\newtheorem{#1@inner}{#3}
}
{
\newtheorem{#1@inner}{#3}[#4]
}
% #1 is not subordinate, store the name itself
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #1 }
\seq_gput_right:Nn \g_riccardo_theorems_counters_seq { #1 }
}
{
\newtheorem{#1@inner}[#2@inner]{#3}
% #1 is subordinate to #2
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #2 }
}
% define a "grabbing" environment #1 with the usual features
\NewEnviron{#1}[1][]
{
% start the inner environment (without or with optional argument)
\tl_if_empty:nTF { ##1 }
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% save the statement number
\tl_gset:Nx \g__riccardo_theorems_number_tl { \use:c {@currentlabel} }
% typeset the statement
\BODY
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
{ #1 } % name
{ \g__riccardo_theorems_number_tl } % number
\IfValueT{##1}{ [\exp_not:n { ##1 }] } % attribution
{ \exp_not:V \BODY } % body
}
}
}
% allocate the needed variables
\prop_new:N \g_riccardo_theorems_prop
\seq_new:N \g_riccardo_theorems_seq
\tl_new:N \g__riccardo_theorems_number_tl
\iow_new:N \g_riccardo_theorems_stream
\seq_new:N \g_riccardo_theorems_counters_seq
% print the stored theorems
\NewDocumentCommand{\printtheorems}{}
{
% we need a group where nullifying the action of \label
\group_begin:
\cs_set_eq:NN \label \use_none:n
% map the sequence, passing each item to the function that prints a theorem
\file_if_exist_input:n { \c_sys_jobname_str.thl }
% end the group
\group_end:
\seq_map_inline:Nn \g_riccardo_theorems_counters_seq
{
\setcounter{##1@inner}{0}
}
}
\cs_new_protected:Nn \riccardo_theorems_save:
{
\seq_map_function:NN \g_riccardo_theorems_seq \__riccardo_theorems_save:n
}
\cs_new_protected:Nn \__riccardo_theorems_save:n
{
\iow_now:Nn \g_riccardo_theorems_stream
{
\savedtheorem #1
}
}
\AtEndDocument
{
\iow_open:Nn \g_riccardo_theorems_stream { \c_sys_jobname_str.thl }
\riccardo_theorems_save:
\iow_close:N \g_riccardo_theorems_stream
}
\NewDocumentCommand{\savedtheorem}{smmom}
{
% redefine \the<statement>@inner to yield the stored number
% we use the property list to use the correct counter
% (for instance, in case of "lemma", <statement> will be "theorem"
\IfBooleanTF{#1}
{
\IfNoValueTF{#4}
{\begin{#2@inner}#5\end{#2@inner}}
{\begin{#2@inner}[#4]#5\end{#2@inner}}
}
{
\cs_set:cpn { the \prop_item:Nn \g_riccardo_theorems_prop {#2} @inner } { #3 }
\IfNoValueTF{#4}
{
% no attribution
\begin{#2@inner} #5 \end{#2@inner}
}
{
% attribution
\begin{#2@inner}[#4] #5 \end{#2@inner}
}
}
}
\ExplSyntaxOff
\newtheoremx*{theorem*}{Theorem}
\newtheoremx{theorem}{Theorem}[section]
\newtheoremx{lemma}[theorem]{Lemma}
\begin{document}
\section{Theorems}
\printtheorems
\section{First test}
\begin{theorem*}
This is not numbered.
\end{theorem*}
\begin{theorem}[Important]\label{thm:important}
This is a theorem about $\log_a x$.
\end{theorem}
\begin{lemma}\label{lem:whatever}
This is a lemma.
\end{lemma}
\begin{theorem}\label{thm:unimportant}
This is another theorem
\end{theorem}
\section{Second test}
\begin{theorem}\label{thm:soandso}
Again a theorem.
\end{theorem}
\end{document}
以下版本需要xparse
发布2019-03-05或更高版本。
\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newtheoremx}{smomo}
{
\IfBooleanTF{#1}
{
\printthm_nonumber:nn { #2 } { #4 }
}
{
\printthm_number:nnnn { #2 } { #3 } { #4 } { #5 }
}
}
\cs_new_protected:Nn \printthm_nonumber:nn
{
\newtheorem*{#1@inner}{#2}
\NewDocumentEnvironment{#1}{ o +b }
{
% start the inner environment (without or with optional argument)
\IfNoValueTF { ##1 }
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% typeset the statement
##2
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
*
{ #1 } % name
{ } % number
\tl_if_novalue:nF { ##1 } { [\exp_not:n { ##1 }] } % attribution
{ \exp_not:n { ##2 } } % body
}
}
{}
}
\cs_new_protected:Nn \printthm_number:nnnn
{
% * Let's duplicate the working of \newtheorem; \newtheoremx should
% be used for theorems that need to be listed
% * \newtheoremx{theorem}{Theorem} will actually do
% \newtheorem{theorem@inner}{Theorem} (honoring the usual optional arguments)
% * We also need a property list to store along with the theorem
% the one which it is subordinate to
\tl_if_novalue:nTF { #2 }
{
\tl_if_novalue:nTF { #4 }
{
\newtheorem{#1@inner}{#3}
}
{
\newtheorem{#1@inner}{#3}[#4]
}
% #1 is not subordinate, store the name itself
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #1 }
\seq_gput_right:Nn \g_riccardo_theorems_counters_seq { #1 }
}
{
\newtheorem{#1@inner}[#2@inner]{#3}
% #1 is subordinate to #2
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #2 }
}
% define a "grabbing" environment #1 with the usual features
\NewDocumentEnvironment{#1}{ o +b }
{
% start the inner environment (without or with optional argument)
\IfNoValueTF{##1}
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% save the statement number
\tl_gset:Nx \g__riccardo_theorems_number_tl { \use:c {@currentlabel} }
% typeset the statement
##2
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
{ #1 } % name
{ \g__riccardo_theorems_number_tl } % number
\IfValueT{##1}{ [\exp_not:n { ##1 }] } % attribution
{ \exp_not:n { ##2 } } } % body
}
{}
}
% allocate the needed variables
\prop_new:N \g_riccardo_theorems_prop
\seq_new:N \g_riccardo_theorems_seq
\tl_new:N \g__riccardo_theorems_number_tl
\iow_new:N \g_riccardo_theorems_stream
\seq_new:N \g_riccardo_theorems_counters_seq
% print the stored theorems
\NewDocumentCommand{\printtheorems}{}
{
% we need a group where nullifying the action of \label
\group_begin:
\cs_set_eq:NN \label \use_none:n
% map the sequence, passing each item to the function that prints a theorem
\file_if_exist_input:n { \c_sys_jobname_str.thl }
% end the group
\group_end:
\seq_map_inline:Nn \g_riccardo_theorems_counters_seq
{
\setcounter{##1@inner}{0}
}
}
\cs_new_protected:Nn \riccardo_theorems_save:
{
\seq_map_function:NN \g_riccardo_theorems_seq \__riccardo_theorems_save:n
}
\cs_new_protected:Nn \__riccardo_theorems_save:n
{
\iow_now:Nn \g_riccardo_theorems_stream
{
\savedtheorem #1
}
}
\AtEndDocument
{
\iow_open:Nn \g_riccardo_theorems_stream { \c_sys_jobname_str.thl }
\riccardo_theorems_save:
\iow_close:N \g_riccardo_theorems_stream
}
\NewDocumentCommand{\savedtheorem}{smmom}
{
% redefine \the<statement>@inner to yield the stored number
% we use the property list to use the correct counter
% (for instance, in case of "lemma", <statement> will be "theorem"
\IfBooleanTF{#1}
{
\IfNoValueTF{#4}
{\begin{#2@inner}#5\end{#2@inner}}
{\begin{#2@inner}[#4]#5\end{#2@inner}}
}
{
\cs_set:cpn { the \prop_item:Nn \g_riccardo_theorems_prop {#2} @inner } { #3 }
\IfNoValueTF{#4}
{
% no attribution
\begin{#2@inner} #5 \end{#2@inner}
}
{
% attribution
\begin{#2@inner}[#4] #5 \end{#2@inner}
}
}
}
\ExplSyntaxOff
\newtheoremx*{theorem*}{Theorem}
\newtheoremx{theorem}{Theorem}[section]
\newtheoremx{lemma}[theorem]{Lemma}
\begin{document}
\section{Theorems}
\printtheorems
\section{First test}
\begin{theorem*}
This is not numbered.
\end{theorem*}
\begin{theorem}[Important]\label{thm:important}
This is a theorem about $\log_a x$.
\end{theorem}
\begin{lemma}\label{lem:whatever}
This is a lemma.
\end{lemma}
\begin{theorem}\label{thm:unimportant}
This is another theorem
\end{theorem}
\section{Second test}
\begin{theorem}\label{thm:soandso}
Again a theorem.
\end{theorem}
\end{document}