仅对数字(整数)输入进行求和

仅对数字(整数)输入进行求和

我有一个自定义命令,它将六个参数用逗号分隔开作为一个参数,然后我使用 将它们分成多个参数\SplitArgument。我需要一个定义命令,它只对数字输入求和,而忽略任何文本,例如“-”。我曾尝试使用包的 定义一个命令xstring\IsInteger但由于我需要对结果数字(除法、乘法)进行一些数学运算,因此这对我来说不起作用。命令没有执行操作,而是“打印”了例如“021 / 24”。我不知道为什么求和的数字前面有一个多余的零,但我怀疑这与不能很好地xstring接受嵌套命令有关。无论如何,我在下面粘贴了我的代码的简化版本。如果有人能帮忙,我将不胜感激。

\documentclass{article}

\usepackage{xparse}

\NewDocumentCommand{\example}{ >{\SplitArgument{5}{,}} m}{\splitexample#1}

\NewDocumentCommand{\splitexample}{mmmmmm}{%
some text, #1, #2, #3, #4, #5, #6, some more text, value inserted by another cmd, value inserted by another cmd, the sum off all the inputs is: %insert sum command here%
}

\begin{document}
\example{1,2,3,4,5,6} %expected output: 21

\example{1, -, 2, -, 3, 4} %expected output: 10
\end{document}

答案1

根据评论请求更新

\documentclass{article}

\makeatletter
\newcommand*\example[1]{\the\numexpr0\example@i{}#1,\hbox\relax}
\def\example@i#1#2{%
    \ifcase
    \ifx\hbox#2\z@\else\ifx,#2\@ne\else\ifnum9<1\string#2 \tw@\else\@M\fi\fi\fi
    % hit end, nothing to do, \relax terminates \the\numexpr
      \expandafter\@gobbletwo
    \or % hit a comma after having seen only digits in this round
      #1+0\expandafter\@firstoftwo
    \or % a digit, accumulate it
      \expandafter\@secondoftwo
    \else % a non-digit gob to comma
      \expandafter\example@continue
    \fi
    {\example@i{}}{\example@i{#1#2}}%
}
\def\example@continue#1,{\example@i{}}
\makeatother

\makeatletter
\newcommand*\example[1]{\the\numexpr0\example@i{}#1,\hbox\relax}
\def\example@i#1#2{%
    \ifcase
    \ifx\hbox#2\z@\else\ifx,#2\@ne\else\ifnum9<1\string#2 \tw@\else\@M\fi\fi\fi
    % hit end, nothing to do, \relax terminates \the\numexpr
      \expandafter\@gobbletwo
    \or % hit a comma after having seen only digits in this round
      #1+0\expandafter\@firstoftwo
    \or % a digit, accumulate it
      \expandafter\@secondoftwo
    \else % a non-digit gob to comma
      \expandafter\example@continue
    \fi
    {\example@i{}}{\example@i{#1#2}}%
}
\def\example@continue#1,{\example@i{}}
\makeatother

\makeatletter
\newcommand*\integerindices[1]{\expanded\integerindices@i0!{}#1,\hbox}
\def\integerindices@i#1!#2#3{%
    \ifcase
    \ifx\hbox#3\z@\else\ifx,#3\@ne\else\ifnum9<1\string#3 \tw@\else\@M\fi\fi\fi
    % hit end
      \expandafter\@firstoffour
    \or % hit a comma directly, increase index and check next one
      \expandafter\@secondoffour
    \or % a digit, dispatch to second auxiliary
      \expandafter\@thirdoffour
    \else % the item starts with a non-digit gob to comma and continue
      \expandafter\@fourthoffour
    \fi
        {{\integerindices@tocsv#2\relax}}% produce in csv format
        {\expandafter\integerindices@i\the\numexpr1+#1!{#2}}%
        {\integerindices@ii#1!{#2}}%
        {\expandafter\integerindices@continue\the\numexpr1+#1!{#2}}%
}
\def\integerindices@continue#1!#2#3,{\integerindices@i#1!{#2}}
\def\integerindices@ii#1!#2#3{%
    \ifcase
    \ifx\hbox#3\z@\else\ifx,#3\@ne\else\ifnum9<1\string#3 \tw@\else\@M\fi\fi\fi
    % hit end
      \expandafter\@firstoffour
    \or % hit a comma after having seen only digits
      \expandafter\@secondoffour
    \or % a digit, keep parsing
      \expandafter\@thirdoffour
    \else % a non-digit gob to comma
      \expandafter\@fourthoffour
    \fi
        % perennial problems of comma separated lists
        % I decided to produce the csv at very end
        {{\integerindices@tocsv#2\relax}}% convert to csv
        {\expandafter\integerindices@i\the\numexpr1+#1!{#2{#1}}}%
        {\integerindices@ii#1!{#2}}%
        {\expandafter\integerindices@continue\the\numexpr1+#1!{#2}}%
}

\long\def\@firstoffour#1#2#3#4{#1}
\long\def\@secondoffour#1#2#3#4{#2}
\long\def\@thirdoffour#1#2#3#4{#3}
\long\def\@fourthoffour#1#2#3#4{#4}

\def\integerindices@tocsv#1{\ifx\relax#1\else#1\expandafter\integerindices@tocsv@i\fi}
\def\integerindices@tocsv@i#1{\ifx\relax#1\else, #1\expandafter\integerindices@tocsv@i\fi}
\makeatother

\begin{document}
This works expandably: \example{a,,2,xyz,40}.

The list of indices starting at zero is for \verb|a,,2,xyz,40|: \integerindices{a,,2,xyz,40}.

 \edef\foo{\integerindices{1,az,32,66,;,87e,35,,,,!!!,99}}
The list of indices starting at zero for \verb|1,az,32,66,;,87e,35,,,,!!!,99| is stored in macro \verb|\foo| with meaning \texttt{\meaning\foo}.

\end{document}

扩展给出整数索引

編輯我已编辑代码,以便逗号分隔列表的逗号后有空格。新屏幕截图:在此处输入图片描述

初步答复

我根据规格编写了这个可扩展的解决方案:

  • 仅非负整数,没有加号,
  • 明确的数字,不隐藏在宏中。

您可以拥有任意多个物品。

\documentclass{article}

\makeatletter
\newcommand*\example[1]{\the\numexpr0\example@i{}#1,\hbox\relax}
\def\example@i#1#2{%
    \ifcase
    \ifx\hbox#2\z@\else\ifx,#2\@ne\else\ifnum9<1\string#2 \tw@\else\@M\fi\fi\fi
    % hit end, nothing to do, \relax terminates \the\numexpr
      \expandafter\@gobbletwo
    \or % hit a comma after having seen only digits in this round
      #1+0\expandafter\@firstoftwo
    \or % a digit, accumulate it
      \expandafter\@secondoftwo
    \else % a non-digit gob to comma
      \expandafter\example@continue
    \fi
    {\example@i{}}{\example@i{#1#2}}%
}
\def\example@continue#1,{\example@i{}}
\makeatother
  

\begin{document}
This works expandably: \example{a,,2,xyz,40}.
\begin{verbatim}
This is now executed:
\ttfamily\parindent0pt
\edef\foo{\example{1,2,3,4,5,6}}% expected output: 21
\meaning\foo\par
\edef\foo{\example{1, -, 2, -, 3, 4}}% expected output: 10
\meaning\foo\par
\edef\foo{\example{a,,2,xyz,40}}% expected output: 42
\meaning\foo\par
\edef\foo{\example{1,az,32,66,;,87e,35,,,,!!!,}}% expected output: 134
\meaning\foo\par
\end{verbatim}
\ttfamily\parindent0pt
\edef\foo{\example{1,2,3,4,5,6}}%expected output: 21
\meaning\foo\par
\edef\foo{\example{1, -, 2, -, 3, 4}}% expected output: 10
\meaning\foo\par
\edef\foo{\example{a,,2,xyz,40}}% expected output: 42
\meaning\foo\par
\edef\foo{\example{1,az,32,66,;,87e,35,,,,!!!,}}% expected output: 134
\meaning\foo\par

\newcounter{mycounter}
\setcounter{mycounter}{\example{,,,,45,!!,^$,&(,text,55}}
\arabic{mycounter}
\end{document}

代码输出

随后我添加了计数器内容演示:

\newcounter{mycounter}
\setcounter{mycounter}{\example{,,,,45,!!,^$,&(,text,55}}
\arabic{mycounter}

再次输出加上反例

答案2

你可以拥有任意数量的项目。当然,命令无法完全扩展。

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\example}{m}
 {
  \atjov_example:n { #1 }
 }

\seq_new:N \l__atjov_example_items_seq
\int_new:N \l__atjov_example_sum_int

\cs_new_protected:Nn \atjov_example:n
 {
  \int_zero:N \l__atjov_example_sum_int
  \seq_set_from_clist:Nn \l__atjov_example_items_seq { #1 }
  \seq_map_function:NN \l__atjov_example_items_seq \__atjov_example_do:n
  \int_use:N \l__atjov_example_sum_int
 }

\cs_new_protected:Nn \__atjov_example_do:n
 {
  \regex_match:nnT { \A [0-9]+ \Z } { #1 }
   {% #1 is an integer
    \int_add:Nn \l__atjov_example_sum_int { #1 }
   }
 }

\ExplSyntaxOff

\begin{document}

\example{1,2,3,4,5,6} %expected output: 21

\example{1, -, 2, -, 3, 4} %expected output: 10

\example{a,,2,xyz,40} % expected: 42

\end{document}

在此处输入图片描述

我们用逗号分隔输入,然后测试每一项是否为非负整数(长度至少为 1 的数字序列);在这种情况下,我们将其添加到特定的整数变量中。最后给出总和。

相关内容