新环境中的复杂参数解析

新环境中的复杂参数解析

我正在尝试用 LaTeX 构建一个发票生成系统,该系统将简单易维护。目前,我们正在使用 longtable 和预处理层。我想将其更改为一.sty组宏,以便模板可以与输入其中的数据更紧密地分离。

我想要的是类似这样的 API:

\begin{invoicetable}{r|llrr|r}{runningnumber,description,qty,sellprice,linetotal}
\heading{runningnumber=\#,partnumber=Partnumber,description=Description,qty=Qty,sellprice=Price,linetotal=Total}
\line{runningnumber=1,partnumber=A-12232,description={Test part, some data},qty=4,sellprice=14.99,linetotal=59.96}
\end{invoicetable}

这将是类似这样的宏(为了清晰起见,这里添加了漂亮的格式):

\begin{longtable}{r|llrr|r}
\# & Partnumber & Description          & Qty & Sellprice & linetotal \\
\endhead
 1 & A-12232    & Test part, some data &   4 &     14.99 &     59.96 \\
\end{longtable}

这样做的几个原因是,它允许我删除环境声明中的列,并忽略行项目中的相关键,并且可以在添加行本身时释放键排序(partnumber = A-12232,qty = 4 无论排序如何都是相同的)。

此时,我对\line宏在这种情况下的工作方式有了很好的了解(我可能会将其命名为\invoiceline),如果我遇到问题,我可以在那里提出更多问题,但我的直接问题是宏的参数\begin。我需要能够大致弄清楚如何在内部获取逗号分隔的值,将它们分解为有序列表和计数器,例如将计数器\invoice@cols作为计数器,并将其\invoice@col@current作为另一个计数器。我认为每个列都需要一个宏,例如\invoice@col1返回列的名称。

答案1

这是一个涉及的解决方案xtring

\documentclass{article}
\usepackage{xstring,longtable}
\makeatletter
\def\line#1{%
    \global\let\tab@keys@i\tab@keys
    \gdef\line@content{#1,}%
    \line@i
}

\def\line@i{%
    \StrCut\tab@keys@i,\current@key\tab@keys@i
    \global\let\tab@keys@i\tab@keys@i
    \IfSubStr\line@content\current@key
        {\StrBehind\line@content\current@key[\current@key]%
        \StrBetween\current@key=,%
        }
        \relax
    \ifx\@empty\tab@keys@i\\%
    \else&\expandafter\line@i
    \fi
}

\def\heading#1{\line{#1}\endhead}

\newenvironment{invoicetable}[2]%
    {\edef\tab@keys{#2,}%
    \expandarg\noexploregroups
    \longtable{#1}%
    }
    \endlongtable

\makeatother
\begin{document}
\begin{invoicetable}{r|llrr|r}{runningnumber,description,qty,sellprice,linetotal}
    \heading{runningnumber=\#,partnumber=Partnumber,description=Description,qty=Qty,sellprice=Price,linetotal=Total}
    \line{runningnumber=1,partnumber=A-12232,description={Test part, some data},qty=4,sellprice=14.99,linetotal=59.96}
\end{invoicetable}
\end{document}

答案2

这是使用 LaTeX3 宏的实现。

\documentclass{article}
\usepackage{longtable}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentEnvironment{invoicetable}{mm} % #1 = columns, #2 = column names
 {
  \travers_invoicetable:n { #2 }
 }
 {
  \begin{longtable}{#1}
  \l_travers_tablehead_tl
  \hline
  \endhead
  \l_travers_table_tl
  \end{longtable}
 }

\NewDocumentCommand{\theading}{m}
 {
  \travers_makeline:Nn \l_travers_tablehead_tl { #1 }
 }

\NewDocumentCommand{\tline}{m}
 {
  \travers_makeline:Nn \l_travers_table_tl { #1 }
 }


\tl_new:N \l_travers_tablehead_tl
\tl_new:N \l_travers_table_tl
\tl_new:N \l__travers_linetemp_tl
\tl_new:N \l_travers_lastcol_tl
\seq_new:N \l_travers_colnames_seq

%%% what to do with unknown keys    
\keys_define:nn { travers/invoice }
 {
  unknown .code:n =
 }

% absorb the list of column names and define the keys
\cs_new_protected:Npn \travers_invoicetable:n #1
 {
  \seq_set_split:Nnn \l_travers_colnames_seq { , } { #1 }
  \seq_map_inline:Nn \l_travers_colnames_seq
   {
    \keys_define:nn { travers/invoice }
     {
      ##1 .tl_set:c = { l__travers_name_##1_tl }
     }
   }
  % detach the last column
  \seq_pop_right:NN \l_travers_colnames_seq \l_travers_lastcol_tl
 }

% each line processes the key-value pairs and adds to the table
\cs_new_protected:Npn \travers_makeline:Nn #1 #2
 {
  \tl_clear:N \l__travers_linetemp_tl
  \keys_set:nn { travers/invoice } { #2 }
  \seq_map_inline:Nn \l_travers_colnames_seq
   {
    \tl_put_right:Nv \l__travers_linetemp_tl { l__travers_name_##1_tl }
    \tl_put_right:Nn \l__travers_linetemp_tl { & }
   }
  \tl_put_right:Nv \l__travers_linetemp_tl { l__travers_name_\l_travers_lastcol_tl _tl }
  \tl_put_right:Nn \l__travers_linetemp_tl { \\ }
  \tl_put_right:NV #1 \l__travers_linetemp_tl
 }

\cs_generate_variant:Nn \tl_put_right:Nn { Nv }

\ExplSyntaxOff

\begin{document}
\begin{invoicetable}{r|llr|r}{
  runningnumber,
  description,
  qty,
  sellprice,
  linetotal
}
\theading{
  runningnumber=\#,
  partnumber=Part number,
  description=Description,
  qty=Qty,
  sellprice=Price,
  linetotal=Total
}
\tline{
  runningnumber=1,
  partnumber=A-12232,
  description={Test part, some data},
  qty=4,
  sellprice=14.99,
  linetotal=59.96
}
\end{invoicetable}

\begin{invoicetable}{r|llrr|r}{
  runningnumber,
  partnumber,
  description,
  qty,
  sellprice,
  linetotal
}
\theading{
  runningnumber=\#,
  partnumber=Part number,
  description=Description,
  qty=Qty,
  sellprice=Price,
  linetotal=Total
}
\tline{
  runningnumber=1,
  partnumber=A-12232,
  description={Test part, some data},
  qty=4,
  sellprice=14.99,
  linetotal=59.96
}
\end{invoicetable}

\begin{invoicetable}{r}{
  linetotal
}
\theading{
  runningnumber=\#,
  partnumber=Part number,
  description=Description,
  qty=Qty,
  sellprice=Price,
  linetotal=Total
}
\tline{
  runningnumber=1,
  partnumber=A-12232,
  description={Test part, some data},
  qty=4,
  sellprice=14.99,
  linetotal=59.96
}
\end{invoicetable}

\end{document}

在此处输入图片描述

相关内容