自动定理列表

自动定理列表

在接受的答案中\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}

相关内容