如何在文档开头自动生成数据摘要?

如何在文档开头自动生成数据摘要?

我希望在我的报告中定义几种结构损坏,并希望在文档开头自动生成汇总表。下面是一个例子,展示了我目前取得的进展以及我想要实现的目标。

\documentclass{article}

\usepackage{etoolbox}
\usepackage{pgffor}

\parindent=0pt

\newcounter{cntClassA}\newcounter{cntClassB}\newcounter{cntClassC}\newcounter{cntAddTmp}

\makeatletter

\newcommand\defineDamageKey[4] { \expandafter\edef\csname damage.#1.#2.#3\endcsname{#4} }

\newcommand{\addDamage}[3]{%
%
    \ifstrequal{#1}{A}{\stepcounter{cntClassA} \setcounter{cntAddTmp}{\thecntClassA} }{}%
    \ifstrequal{#1}{B}{\stepcounter{cntClassB} \setcounter{cntAddTmp}{\thecntClassB} }{}%
    \ifstrequal{#1}{C}{\stepcounter{cntClassC} \setcounter{cntAddTmp}{\thecntClassC} }{}%
%
    \defineDamageKey{#1}{\thecntAddTmp}{description}{#2}%
    \defineDamageKey{#1}{\thecntAddTmp}{solution}{#3}%
    \defineDamageKey{#1}{\thecntAddTmp}{ID}{#1-\thecntAddTmp}%
%
    \printDamage{#1}{\thecntAddTmp}%
}

\newcommand{\printDamage}[2]{%
    \textbf{ID:} \@nameuse{damage.#1.#2.ID}\\%
    \textbf{Damage class:} #1\\%
    \textbf{Description:} \@nameuse{damage.#1.#2.description}\\%
    \textbf{Solution:} \@nameuse{damage.#1.#2.solution}\\%
}

\newcommand{\damageSummary}[1]{%
    \newcount\damageCountForClass
%
    \ifstrequal{#1}{A}{ \damageCountForClass=\thecntClassA }{}%
    \ifstrequal{#1}{B}{ \damageCountForClass=\thecntClassB }{}%
    \ifstrequal{#1}{C}{ \damageCountForClass=\thecntClassC }{}%
%
    \foreach \n in {1,...,\damageCountForClass}%
    {%
        \textbf{\@nameuse{damage.#1.\n.ID}:} \@nameuse{damage.#1.\n.description}\\
    }%
}

\makeatother

\begin{document}

\section{Building 1}

\addDamage{A}{Broken window}{Fix window}

\addDamage{B}{Wrong wall paint}{Repaint}


\section{Building 2}

\addDamage{C}{Leaky windows}{Seal windows}

\addDamage{A}{Defective electrics}{Fix electrics}


\section{Summary}

\damageSummary{A}
\damageSummary{B}
\damageSummary{C}


\end{document}

在此处输入图片描述

我的基本想法是将我的数据定义为具有结构化命名宏的键/值对:

\@namedef{damage.A.1.description}{description damage A-1}
\@namedef{damage.A.1.solution}{solution damage A-1}
\@namedef{damage.A.2.description}{description damage A-2}

但现在我想在文档开头显示摘要表!我说的对吗?这只适用于 AUX 文件?

我刚刚开始学习低级 TeX / 宏编写,并试图通过检查 todonotes 包(因为可能存在类似的机制)来弄清楚如何做到这一点\todo\listoftodos但我不明白。

那么我当前的解决方案是否真的是一个很好的起点,还是我需要不同的方法?有人能给我提示如何实现这一点吗?

答案1

编辑:如果您希望从摘要中建立超链接到描述损坏的文档位置,则可以添加 hyperref-support。

如果您不介意有一个辅助文件,其名称是每个损坏类别的模式,那么您可能可以使用 LaTeX 2ε 的- -meachanism。我使用-environments 来列出项目。如何调整-environment 取决于正在使用的文档类,并且可能会变得棘手。⟨expansion of jobname⟩.Damageclass⟨name of damage-class⟩\addtocontents\@starttocdescriptiondescription

这个例子需要编译三次,每次运行之间不能删除辅助文件,直到一切都正确匹配。(第一次运行创建辅助文件。第二次运行创建摘要的描述项标签并将测量值存储在辅助文件中。第三次运行使用辅助文件中的测量值。)

\documentclass{article}
\usepackage{hyperref}

\makeatletter
\newcommand\maxIDwidth{0pt}%
\AtBeginDocument{\providecommand\r@maxIDwidthpreviousrun{0pt}}%
\AtEndDocument{%
  \protected@write\@auxout{}{\string\newlabel{maxIDwidthpreviousrun}{\maxIDwidth}}%
}%
\DeclareRobustCommand\damageSummaryItem[3]{%
  \item[%
    \setbox\scratchbox\hbox{#1}%
    \ifdim\maxIDwidth<\wd\scratchbox\xdef\maxIDwidth{\the\wd\scratchbox}\fi
    \rlap{\hbox{\@ifundefined{hyperlink}{\@secondoftwo}{\hyperlink}{#3}{#1}}}%
    \hbox to\r@maxIDwidthpreviousrun{\hfill}%
  ]%
  #2%
}%
\newbox\scratchbox
\newcommand\addDamage[3]{%
   %#1 - Damage class
   %#2 - Damage description
   %#3 - Fix/Solution description
   \@ifundefined{c@Damageclass@#1}{%
     \newcounter{Damageclass@#1}%
     \expandafter\gdef\csname theDamageclass@#1\endcsname{#1\mbox{-}\arabic{Damageclass@#1}}%
   }{}%
   \begingroup
   \begin{description}%
   \itemsep=0pt
   \parskip=0pt
   \item[{\refstepcounter{Damageclass@#1}ID:%
     \addtocontents{Damageclass#1}{%
       \damageSummaryItem{\csname theDamageclass@#1\endcsname:}{#2}{\@ifundefined{@currentHref}{}{\@currentHref}}\protected@file@percent
     }%
   }]\csname theDamageclass@#1\endcsname
   \item[{Damage class:}]#1%
   \item[{Description:}]#2%
   \item[{Solution:}]#3%
   \end{description}%
   \endgroup
}%
\newcommand\damageSummary[1]{%
  \begingroup
  \IfFileExists{\jobname.Damageclass#1}{%
    \@ifundefined{hyperlink}{\@firstoftwo}{%
      {\expandafter}\expandafter\ifx\csname hyper@last\endcsname\relax
      \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
    }%
  }{\@secondoftwo}%
  {%
    \begin{description}%
    \itemsep=0pt
    \parskip=0pt
    \@starttoc{Damageclass#1}%
    \par\vskip-\@topsepadd\vskip-\parskip
    \end{description}%
  }{\@starttoc{Damageclass#1}}%
  \endgroup
}%
\makeatother

\begin{document}

\section{Summary}
\damageSummary{A}
\damageSummary{B}
\damageSummary{C}

\section{Building 1}

\addDamage{A}{Broken window}{Fix window}

\addDamage{B}{Wrong wall paint}{Repaint}

\section{Building 2}

\addDamage{C}{Leaky windows}{Seal windows}

\addDamage{A}{Defective electrics}{Fix electrics}

\end{document}

在此处输入图片描述

问题“使用 LaTeX 制作零件清单吗?”你可能会对这个问题的答案感兴趣——那里也提到了类似的问题。在答案中,你会发现一种不同的方法,它基于包数据工具和一个.csv 文件。

答案2

你是对的:你需要一个辅助文件。

.dam如果文件与之前的运行不同,以下代码将发出警告并告诉您重新运行 LaTeX。

\documentclass{article}

\ExplSyntaxOn

% the user interface
\NewDocumentCommand{\addDamage}{mmm}
 {% #1 = class, #2 = type, #3 = action
  \cryptkeeper_damage_add:nnn { #1 } { #2 } { #3 }
 }
\NewDocumentCommand{\printDamageSummary}{}
 {
  \section*{Summary}
  \cryptkeeper_damage_print:
 }
% the auxiliary command
\NewDocumentCommand{\damageSummary}{mmm}
 {
  \cryptkeeper_damage_add_summary:nnn { #1 } { #2 } { #3 }
 }

% the lower level code

% variables
\iow_new:N \g_cryptkeeper_damage_iow
\prop_new:N \g_cryptkeeper_damage_prop
\str_new:N \g_cryptkeeper_damage_hash_str
\int_new:N \g_cryptkeeper_damage_class_A_int
\int_new:N \g_cryptkeeper_damage_class_B_int
\int_new:N \g_cryptkeeper_damage_class_C_int
\seq_new:N \g_cryptkeeper_damage_id_seq

% actions for setup
\AtBeginDocument
 {
  \file_if_exist:nT { \c_sys_jobname_str.dam }
   {% the file exists, save its hash and input it
    \str_gset:Nx \g_cryptkeeper_damage_hash_str
     {
      \file_mdfive_hash:n { \c_sys_jobname_str.dam }
     }
    \file_input:n { \c_sys_jobname_str.dam }
   }
  \iow_open:Nn \g_cryptkeeper_damage_iow { \c_sys_jobname_str.dam }
 }
\AtEndDocument
 {
  \iow_close:N \g_cryptkeeper_damage_iow
  \str_if_eq:eeF
   { \g_cryptkeeper_damage_hash_str } % saved hash
   { \file_mdfive_hash:n { \c_sys_jobname_str.dam } } % new hash
   {% if differ, issue a message
    \msg_warning:nn { cryptkeeper/damage } { file differ }
   }
 }

% messages
\msg_new:nnn { cryptkeeper/damage } { file differ }
 {
  .dam~file~modified.~Rerun~LaTeX.
 }

\cs_new_protected:Nn \cryptkeeper_damage_add:nnn
 {
  % increment the counter
  \int_gincr:c { g_cryptkeeper_damage_class_#1_int }
  % write a the .dam file
  \iow_now:Nx \g_cryptkeeper_damage_iow
   {
    \exp_not:N \damageSummary % the command
    {#1} % the class
    { \int_use:c { g_cryptkeeper_damage_class_#1_int } } % the number
    { \exp_not:n { #2 } } % the damage
   }
  % print the data
  \par\addvspace{\topsep}
  \noindent
  \textbf{ID:}~#1-\int_use:c { g_cryptkeeper_damage_class_#1_int } \\*
  \textbf{Damage~class:}~#1 \\*
  \textbf{Description:}~#2 \\*
  \textbf{Solution:}~#3
  \par\addvspace{\topsep}
 }

\cs_new_protected:Nn \cryptkeeper_damage_add_summary:nnn
 {
  % save the ID in the form {1|2|3}000+damage number
  % class A is 1, and so on
  % the sequence will be sorted by \printSummary
  \seq_gput_right:Nx \g_cryptkeeper_damage_id_seq
   { \int_eval:n { \int_from_alph:n { #1 } * 1000 + #2 } }
  % save the data in a property list
  \prop_gput:Nen \g_cryptkeeper_damage_prop
   { \int_eval:n { \int_from_alph:n { #1 } * 1000 + #2 } }
   {
    \noindent\textbf{#1-#2:}~#3\par
   }
 }
\cs_generate_variant:Nn \prop_gput:Nnn { Ne }

\cs_new_protected:Nn \cryptkeeper_damage_print:
 {
  % sort the sequence
  \seq_sort:Nn \g_cryptkeeper_damage_id_seq
   {
    \int_compare:nTF { ##1 > ##2 } { \sort_return_swapped: } { \sort_return_same: }
   }
  % map the sequence and print the data stored in the property list
  \seq_map_inline:Nn \g_cryptkeeper_damage_id_seq
   {
    \prop_item:Nn \g_cryptkeeper_damage_prop { ##1 }
   }
 }

\ExplSyntaxOff

\begin{document}

\printDamageSummary

\section{Building 1}

\addDamage{A}{Broken window}{Fix window}

\addDamage{B}{Wrong wall paint}{Repaint}


\section{Building 2}

\addDamage{C}{Leaky windows}{Seal windows}

\addDamage{A}{Defective electrics}{Fix electrics}

\end{document}

注意\printSummary可以去任何地方。

在此处输入图片描述

答案3

使用memory包存储任意自由格式n维数据,使用tocloft包通过命令收集磁盘上的摘要信息\addtocontents(虽然\addcontentsline也有效并提供 TOC 页码),并使用非常简单的 expl3 语法对类、类计数器和待办事项进行嵌套循环来创建摘要(用于排序):

概括

目前在某些地方是硬编码的,但可以动态扩展(例如,创建新的类计数器或计算循环端点)。

并且使用memory包,添加额外的维度(例如建筑领域)变得微不足道。

平均能量损失

\documentclass{article}
\usepackage[table]{xcolor}
\usepackage{tocloft}
\newlistof{todos}{ltd}{Summary}
\usepackage{memory}
\usepackage{etoolbox}
\usepackage{xparse}



\newcounter{todoitem}
\newcounter{classcounterA}
\newcounter{classcounterB}
\newcounter{classcounterC}
\newcounter{classcounterZ}
\newcounter{classcountertemp}


\ExplSyntaxOn


\int_new:N \l_myclassfirst_int
\int_new:N \l_myclasslast_int
\int_new:N \l_myclasscountmax_int
\int_new:N \l_mytempc_int
\int_new:N \l_mytempd_int


\int_new:N \l_myloopcount_int
\int_new:N \l_myloopcountcc_int
\int_new:N \l_mytodoloopcount_int
\int_new:N \l_mytodocountmax_int



\str_new:N \l_mytemp_str
\str_new:N \l_mytempb_str
\str_new:N \l_mytempc_str
\str_new:N \l_mytempd_str
\str_new:N \l_mytodototal_str

\NewDocumentCommand { \summarytodos } { } {

  %
    \int_set:Nn \l_myclassfirst_int { 
                                                                \int_from_alph:n { A }
                                                                                                 }

    \int_set:Nn \l_myclasslast_int { 
                                                                \int_from_alph:n { Z }
                                                                                                 }

  
   %
   \int_set:Nn \l_myloopcount_int { \c_zero_int }
   
   % loop through the classes (A-Z)
   \int_do_while:nNnn 
                    { \l_myloopcount_int } <  { \l_myclasslast_int } 
                    { 
                        \int_set:Nn 
                                    \l_myloopcount_int 
                                    { \l_myloopcount_int + 1 }

                 { 
                   % loop through the class counters
                   \int_set:Nn \l_myloopcountcc_int { \c_one_int }
                   \int_set:Nn \l_myclasscountmax_int { 15 } %
                   \int_do_while:nNnn 
                                    { \l_myloopcountcc_int } <  { \l_myclasscountmax_int } 
                                    { 
                                     { 

%--------------- loop through all the todo items
%--------------- if there is a match on class + classcounter
%---------------    then print               
%                   \alltodos[total]
                    \str_set:Nx \l_mytofototal_str { 
                                        \cs:w @alltodos@total@memory\cs_end:
                                                            }

                    \int_set:Nn \l_mytodoloopcount_int { \c_one_int }
                    \int_set:Nn \l_mytodocountmax_int { \l_mytofototal_str + 1} 
                   \int_do_while:nNnn 
                                    { \l_mytodoloopcount_int } 
                                    <  
                                    { \l_mytodocountmax_int } 
                                    { %true
                                    
                                    %match on class:
\str_set:Nx \l_mytemp_str { 
                    \cs:w @blist@\int_use:N\l_mytodoloopcount_int,\lbdimb @memory\cs_end:
                                        }
                                                
\str_set:Nx \l_mytempb_str { 
                                                    \int_to_Alph:n { \l_myloopcount_int }
                                                }
                                                
  %
\str_if_eq:NNTF
                                     \l_mytempb_str
                                     \l_mytemp_str
                {                                   
                                    %match on class counter:
                    \str_set:Nx \l_mytempc_str { 
                                        {\cs:w @blist@\int_use:N\l_mytodoloopcount_int,\lbdimc @memory\cs_end:}
                                                            }
                                                                    
                    \str_set:Nx \l_mytempd_str { 
                                                                        { \int_eval:n { \l_myloopcountcc_int } }
                                                                    }
                                                                    
                      %
                    \str_if_eq:NNTF
                                                         \l_mytempc_str
                                                         \l_mytempd_str
        {                                   

                        % add to summary
            \addtocontents{ltd}{%        
%                           List:
                    {\bfseries
%%              :\cs:w 
%%                      @blist@\int_use:N\l_mytodoloopcount_int,\lbdima @memory
%%                      \cs_end:
                \cs:w 
                        @blist@\int_use:N\l_mytodoloopcount_int,\lbdimb @memory
                        \cs_end:
                        -
                \cs:w 
                        @blist@\int_use:N\l_mytodoloopcount_int,\lbdimc @memory
                        \cs_end:
                        }%end bfseries
                        :~~ % space
                \cs:w 
                        @blist@\int_use:N\l_mytodoloopcount_int,\lbdimd @memory
                        \cs_end:
%%%%                :\cs:w 
%%%                     @blist@\int_use:N\l_mytodoloopcount_int,\lbdime @memory
%%%                     \cs_end:
%%%             :\cs:w 
%%%                     @blist@\int_use:N\l_mytodoloopcount_int,\lbdimf @memory
%%%                     \cs_end:
                    \par
                    }% end addtocontens
                        }{}% end match on class counter
                        }{}% end match on class
                        \int_set:Nn 
                                    \l_mytodoloopcount_int 
                                    { \l_mytodoloopcount_int + \c_one_int }


                                            }{}% todo loop

                                                }{}% class counter loop

                        \int_set:Nn 
                                    \l_myloopcountcc_int 
                                    { \l_myloopcountcc_int + \c_one_int }
                 
                                }% class counter loop
                 }
                 {  }

                        
                        
                    } % end class loop
                    
                        \addtocontents{ltd}{\protect\mbox{}\protect\hrulefill\par}
   
}

\ExplSyntaxOff



\newcommand\lbdimbuilding{building}
\newcommand\lbdimdclass{dclass}
\newcommand\lbdimdclasscounter{dclasscounter}
\newcommand\lbdimdescription{description}
\newcommand\lbdimsolution{solution}
\newcommand\lbdimstatus{status}

\newdata*{blist}
\newdata{alltodos}
\newdata{tempblist}





%-------------------------------
\newcommand\lbdima{\lbdimbuilding}
\newcommand\lbdimb{\lbdimdclass}
\newcommand\lbdimc{\lbdimdclasscounter}
\newcommand\lbdimd{\lbdimdescription}
\newcommand\lbdime{\lbdimsolution}
\newcommand\lbdimf{\lbdimstatus}

\newcommand\lbclasscountername{}



%-------------------------------
\newcommand\addtodo[4]{%
    \stepcounter{todoitem}
\blist[\thetodoitem,\lbdima]={#1}
\blist[\thetodoitem,\lbdimb]={#2}
\expandafter\renewcommand\expandafter\lbclasscountername{classcounter#2}
%\lbclasscountername
\stepcounter{\lbclasscountername}
\setcounter{classcountertemp}{\value{\lbclasscountername}}
\blist[\thetodoitem,\lbdimc] := {\theclasscountertemp}%{\lbclasscountername}
\blist[\thetodoitem,\lbdimd]={#3}
\blist[\thetodoitem,\lbdime]={#4}
\blist[\thetodoitem,\lbdimf]={To do}
\alltodos[total]=\thetodoitem
\printtodoitem{\thetodoitem}
}


%-------------------------------
\newcommand\printtodoitem[1]{%
\begin{tabular}{ll}
\rowcolor{blue!20}
{\Large {\phantom{L}}} Item & \\
\hline
%\blist[\thetodoitem,\lbdima]
\bfseries ID & \blist[\thetodoitem,\lbdimb]-\blist[\thetodoitem,\lbdimc] \\
\bfseries Class & \blist[\thetodoitem,\lbdimb]\\
\bfseries Description & \blist[\thetodoitem,\lbdimd]\\
\bfseries Solution & \blist[\thetodoitem,\lbdime]
%\blist[\thetodoitem,\lbdimf]
\end{tabular}
\hspace{1in}
%\par
%\bigskip
}


%-------------------------------
\newcommand\showalltodostotal{\alltodos[total]\ items in total.}


\begin{document}
\listoftodos


\section{b1}

\addtodo{(b1)}{A}{Broken window}{Fix window}
\addtodo{(b1)}{B}{Wrong wall paint}{Repaint}

\section{b2}

\addtodo{(b2)}{C}{Leaky windows}{Seal windows}
\addtodo{(b2)}{A}{Defective electrics}{Fix electrics}


\section{b3}

\addtodo{(b3)}{Z}{Too sunny}{Put sunshade up}
\addtodo{(b3)}{Z}{No solar panels}{Install solar panels}

\section{b4}

\showalltodostotal
\summarytodos

\end{document}

相关内容