我有一个自定义命令,它将六个参数用逗号分隔开作为一个参数,然后我使用 将它们分成多个参数\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 的数字序列);在这种情况下,我们将其添加到特定的整数变量中。最后给出总和。