好些了吗?答案

好些了吗?答案

我正在尝试实现这样的目标:

\newcommand{\test}[2]{#1 & :={#2} € & :={[-2,0] * [-1,0]} € \\}

\begin{spreadtab}{{tabularx}{\textwidth}{|X|r|r|}}
@ Col 1 & @ Col 2 & @ Col 3 \\
\hline
\test{2}{50}
\test{3}{100}
\hline
\multicolumn{2}{|r|}{@ Total} & :={sum(c2:[0,-1])} € \\
\end{spreadtab}

这不起作用,它只显示公式而不是结果。

我知道公式无法被处理因为它们在命令中,但我不知道如何解决它。

----- 5 个月后编辑 -----

接受的答案对于我所问的问题来说是一个很好的答案,但是过了一段时间却无法真正得到我想要的东西,我放弃了它,等有时间的时候再回来,用另一种技术,根本不使用spreadtab(这是一个很好的模块,但不适合我的情况)。

对于那些阅读这个问题的人,这是我的解决方案:

\newcounter{total}
\setcounter{total}{0}
\newcommand{\test}[2]{
    \addtocounter{total}{\fpeval{#1 * #2}}
    #1 & #2 € & {\fpeval{#1 * #2} €} \\
}

\begin{tabularx}{\textwidth}{|X|r|r|}
Col 1 & Col 2 & Col 3 \\
\hline
\test{2}{50}
\test{3}{100}
\hline
\multicolumn{2}{|r|}{Total} & \the\numexpr\value{total} € \\
\end{tabularx}

这是一个比我想要的更长的解决方案,带有“手动”公式,但效果很好。

答案1

好些了吗?答案

一种不需要您将其放在\noexpand任何地方的变体,但仅扩展一组已定义的宏(按照您添加这些宏的顺序)。宏需要可扩展且一步扩展(因此,没有可选参数,也没有太花哨的东西,即使它们需要更多,它们仍然只会扩展一次)。应该扩展的宏不能位于任何括号组中,因为这样它们将无法找到并且不会扩展。

\AddXspreadtabMacro在 主体中应展开的宏上使用Xspreadtab,也可以使用\RemXspreadtabMacro从列表中删除应展开的宏。\Add...和均\RemXspreadtabMacro在本地范围内工作。

\documentclass[]{article}

\usepackage{tabularx}
\usepackage{spreadtab}
\usepackage{xparse}

\ExplSyntaxOn
% will store the body of the spreadtab on which we're working
\tl_new:N \l_guildem_spreadtab_tl
% will store the macro names which should be expanded
\seq_new:N \l_guildem_expansion_seq
% used to signal that we should do another expansion loop for a macro
\bool_new:N \l__guildem_loop_bool
% add the macro to the list of macros which should be expanded
\NewDocumentCommand \AddXspreadtabMacro { m }
  {
    \seq_if_in:NnF \l_guildem_expansion_seq { #1 }
      {
        \seq_put_right:Nn \l_guildem_expansion_seq { #1 }
      }
  }
% remove a macro from the list
\NewDocumentCommand \RemXspreadtabMacro { m }
  {
    \seq_remove_all:Nn \l_guildem_expansion_seq { #1 }
  }
\cs_new_protected:Npn \__guildem_sanitize_spreadtab_aux:w #1 \q_nil \q_stop
  {
    \tl_set:No \l_guildem_spreadtab_tl { \use_none:n #1 }
  }
\cs_new_protected:Npn \__guildem_sanitize_spreadtab:
  {
    \exp_after:wN
    \__guildem_sanitize_spreadtab_aux:w \l_guildem_spreadtab_tl \q_stop
  }
\cs_new_protected:Npn \__guildem_expand_macro:n #1
  {
    % check whether the macro is in the body of the spreadtab
    \tl_if_in:NnT \l_guildem_spreadtab_tl { #1 }
      {
        \bool_set_true:N \l__guildem_loop_bool
        % define a helper function that expands the macro
        \cs_set:Npn \__guildem_expand_macro_aux:w ##1 #1 ##2 \q_stop
          {
            \tl_set:Nn \l_guildem_spreadtab_tl { ##1 }
            \tl_put_right:No \l_guildem_spreadtab_tl { #1 ##2 }
          }
      }
    % \l__guildem_loop_bool is true as long as the macro is still contained in
    % the body and not yet expanded
    \bool_while_do:Nn \l__guildem_loop_bool
      {
        % call the helper macro that expands the macro
        \exp_after:wN
        \__guildem_expand_macro_aux:w \l_guildem_spreadtab_tl \q_stop
        % check whether there is another occurrence of macro in the body
        \tl_if_in:NnF \l_guildem_spreadtab_tl { #1 }
          { \bool_set_false:N \l__guildem_loop_bool }
      }
  }
\cs_new_protected:Npn \__guildem_spreadtab:nn #1 #2
  {
    \begin{spreadtab}#1#2\end{spreadtab}
  }
\cs_generate_variant:Nn \__guildem_spreadtab:nn { nV }
\NewDocumentEnvironment{Xspreadtab}{O{} m b}
  {
    % adding \q_nil on both sides to not accidentally remove a group while later
    % parsing.
    \tl_set:Nn \l_guildem_spreadtab_tl { \q_nil #3 \q_nil }
    % step over the macros which should be expanded and expand those
    \seq_map_function:NN \l_guildem_expansion_seq \__guildem_expand_macro:n
    % remove the \q_nil from both ends
    \__guildem_sanitize_spreadtab:
    % output the spreadtab
    \__guildem_spreadtab:nV { [{#1}]{#2} } \l_guildem_spreadtab_tl
  }
  {}
\ExplSyntaxOff

\newcommand{\test}[2]{#1 & :={#2} € & :={[-2,0] * [-1,0]} €}
\AddXspreadtabMacro\test

\begin{document}
\begin{Xspreadtab}{{tabularx}{\textwidth}{|X|r|r|}}
@ Col 1 & @ Col 2 & @ Col 3 \\
\hline
\test{2}{50} \\
\test{3}{100} \\
\hline
\multicolumn{2}{|r|}{@ Total} & :={sum(c2:[0,-1])} € \\
\end{Xspreadtab}
\end{document}

原始答案

问题是,spreadtab在搜索公式之前不会扩展其内容。理论上,您可以创建一个类似于的环境,spreadtab但在将其转发到之前会扩展其内容spreadtab,但这需要\noexpand在每个不应扩展的宏之前放置,因此输入实际上并不会变得更容易。

\documentclass[]{article}

\usepackage{tabularx}
\usepackage{spreadtab}

\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \Xspreadtab_expansion_helper:nn #1 #2 { #1 #2 }
\cs_generate_variant:Nn \Xspreadtab_expansion_helper:nn { nx }
\NewDocumentEnvironment{Xspreadtab}{O{} m b}
  {
    \Xspreadtab_expansion_helper:nx { \begin{spreadtab}[{#1}]{#2} } { #3 }
    \end{spreadtab}
  }
  {}
\ExplSyntaxOff

\newcommand{\test}[2]{#1 & :={#2} € & :={[-2,0] * [-1,0]} €}

\begin{document}
\begin{Xspreadtab}{{tabularx}{\textwidth}{|X|r|r|}}
@ Col 1 & @ Col 2 & @ Col 3 \noexpand\\
\noexpand\hline
\test{2}{50} \noexpand\\
\test{3}{100} \noexpand\\
\noexpand\hline
\noexpand\multicolumn{2}{|r|}{@ Total} & :={sum(c2:[0,-1])} € \noexpand\\
\end{Xspreadtab}
\end{document}

相关内容