![修改现有的迭代代码](https://linux22.com/image/353233/%E4%BF%AE%E6%94%B9%E7%8E%B0%E6%9C%89%E7%9A%84%E8%BF%AD%E4%BB%A3%E4%BB%A3%E7%A0%81.png)
我最近在网上发现了这段代码,它完全可以帮助我解决我遇到的一个问题。代码如下:
\documentclass{article}
\usepackage{catoptions}
\makeatletter
\robust@def*\inputcommandnames{\cpt@testopt\@inputcommandnames{general}}
\newletcs\inputcommandname\inputcommandnames
% #1=stack name, #2=input name(s)
\robust@def*\@inputcommandnames[#1]#2{%
\ifblankFT{#1}{%
\@latex@info{No stack name given: using 'general' instead}%
}{%
% It is possible to iterate over stack names, but leave this for now:
% the use case isn't yet apparent.
\ifinsetTF,{#1}{%
\@latexerr{List '#1' not allowed}\@ehd
}{}%
}%
\ifcsndefTF{name@stack@#1}{}{\csn@def{name@stack@#1}{}}%
\ifcsndefTF{name@stackcount@#1}{}{\csn@def{name@stackcount@#1}{0}}%
\cptdocommalist{#2}{%
\csn@edef{name@stackcount@#1}%
{\the\numexpr\usename{name@stackcount@#1}+1}%
\csn@edef{name@stack@#1}{%
\expandcsnonce{name@stack@#1}\noexpand
\do{\usename{name@stackcount@#1}}{\unexpanded{##1}}%
}%
}%
}
\robust@def*\outputinnormalorder{\@outputcommandnames{normal}}
\newletcs\outputcommandnames\outputinnormalorder
\robust@def*\outputinreverseorder{\@outputcommandnames{reverse}}
% #1=listing/printing order, #2=stack name(s)
\robust@def*\@outputcommandnames#1#2{%
\cptdocommalist{#2}{%
\begingroup
\let\reserved@a\relax
\ifcsndefTF{name@stack@##1}{%
% If the stack is defined but it is currently empty, ignore it
% (but issue a warning). A 'verbose' option for triggering the
% warning will be useful here, but it hasn't been provided:
\ifcsnnullFT{name@stack@##1}{}{%
\@latex@info{Stack '##1' is empty}%
\def\reserved@a####1\endgroup{\endgroup}%
}%
}{%
\@latexerr{Stack '##1' is not defined}\@ehd
}%
\reserved@a
\xifstrcmpTF{#1}{normal}{%
\let\do\curroutputformat
\csname name@stack@##1\endcsname
}{%
\def\name@sentinel####1\name@stop{%
\let\do\curroutputformat####1%
}%
\def\do####1####2####3\name@sentinel####4\name@stop{%
####3\name@sentinel\do{####1}{####2}####4\name@stop
}%
\usename{name@stack@##1}\name@sentinel\name@stop
}%
\endgroup
}%
}
% \commandnameoutputformat<input no.><input item>
\robust@def*\commandnameoutputformat{%
% Skip any spurious spaces before opening brace:
\begingroup
\toks0{##1##2}%
\def\reserved@a{%
\expandafter\endgroup\expandafter\def\expandafter
\curroutputformat\the\toks\expandafter0\expandafter{\the\toks1}%
}%
\afterassignment\reserved@a\toks1=%
}
% If the stack isn't initialized after use, it will start building
% from the last count whenever it is called:
\robust@def*\initializecommandstacks#1{%
\cptdocommalist{#1}{%
\csn@def{name@stackcount@##1}{0}%
\csn@def{name@stack@##1}{}%
}%
}
\newletcs\initializecommandstack\initializecommandstacks
% Set empty stack 'xx' for warning later:
\csn@def{name@stack@xx}{}
\makeatother
% Examples:
\begin{document}
\inputcommandname{I wanted this whole sentence on this input, but when I use a comma it breaks the input and starts a new one}
\inputcommandname{If I don't use commas then it's ok}
\commandnameoutputformat{Input number #1 is: #2.\par}
Output:\par
\outputinnormalorder{general}
\end{document}
所以,问题就在这里:我希望代码能够完全按照它的功能运行(存储迭代命令的变量),但每次输入逗号时都不会自动创建新的输入。我一直试图改变它,但每次都失败了。你们能修改它,让它以这种方式工作吗(没有“逗号中断”)?谢谢你们的关注。
答案1
您可以使用以下方法获取灵活的代码expl3
:
\documentclass{article}
\usepackage{xparse}
\usepackage{booktabs} % for the last example
\ExplSyntaxOn
% first define the user interface
\NewDocumentCommand{\addtolist}{O{general}m}
{
\marinho_lists_add:nn { #1 } { #2 }
}
\NewDocumentCommand{\listoutputformat}{+m}
{
\marinho_lists_output_format:n { #1 }
}
\NewDocumentCommand{\outputlist}{m}
{
\marinho_lists_output:n { #1 }
}
% define the internal functions
\cs_new_protected:Nn \marinho_lists_add:nn
{
% create the sequence if it doesn't exist
\seq_if_exist:cF { l_marinho_lists_#1_seq }
{
\seq_new:c { l_marinho_lists_#1_seq }
}
% add the item in the form {<number>}{<text>}
\seq_put_right:cx { l_marinho_lists_#1_seq }
{% compute the number based on the sequence length
{ \int_to_arabic:n { \seq_count:c { l_marinho_lists_#1_seq } + 1 } }
{ \exp_not:n { #2 } }
}
}
\cs_new_protected:Nn \marinho_lists_output_format:n
{% the private function holds the format
\cs_set:Nn \__marinho_lists_output_current:nn { #1 }
}
\marinho_lists_output_format:n { #1~--~#2 \par } % a default
\cs_new_protected:Nn \marinho_lists_output:n
{% map the sequence using the current format
\seq_map_function:cN { l_marinho_lists_#1_seq } \__marinho_lists_item:n
}
\cs_new:Nn \__marinho_lists_item:n
{% \__marinho_lists_item:n receives an argument in the form {<number>}{<text>}
% which we pass to \__marinho_lists_output_current:nn as two arguments
\__marinho_lists_output_current:nn #1
}
\ExplSyntaxOff
\setlength{\parindent}{0pt} % just for this example
\begin{document}
\section{Fill in the lists}
This section will have no other output.
\addtolist{%
I wanted this whole sentence on this input, even with commas,
without breaking the sentence
}
\addtolist{If I don't use commas then it's ok}
\addtolist[another]{Some text to go first}
\addtolist[another]{Some text to go second}
\addtolist[another]{Some text to go third}
\addtolist{This is in the general list}
\section{Output the \texttt{general} list}
\listoutputformat{Input number #1 is: #2\par}
\outputlist{general}
\section{Output the list named \texttt{another}}
{%
\listoutputformat{(#1) #2\par}
\outputlist{another}
}
\bigskip
Since the code above was in a group, the \texttt{general}
list will now be output identically as before.
\bigskip
\outputlist{general}
\section{We can do in a \texttt{tabular}}
\listoutputformat{#1 & #2 \\}% for a table
\begin{tabular}{ll}
\toprule
N & \multicolumn{1}{c}{Text} \\
\midrule
\outputlist{another}
\bottomrule
\end{tabular}
\end{document}
如果不带可选参数,\addtolist
则添加到“常规”列表。您可以根据需要定义任意数量的列表。输出列表时,\listoutputformat
如果默认格式不合适,请使用命令。这尊重分组,如示例所示。
最后的例子表明您可以使用\outputlist
宏来构建表格,只要列表中的每个项目都形成一个表格行。
不同的版本允许您重新开始计数\addtolist*
(仍然允许使用多个列表)。
\documentclass{article}
\usepackage{xparse}
\usepackage{booktabs} % for the last example
\ExplSyntaxOn
% first define the user interface
\NewDocumentCommand{\addtolist}{sO{general}m}
{
\IfBooleanTF{#1}
{ \marinho_lists_add_restart:nn { #2 } { #3 } }
{ \marinho_lists_add_continue:nn { #2 } { #3 } }
}
\NewDocumentCommand{\listoutputformat}{+m}
{
\marinho_lists_output_format:n { #1 }
}
\NewDocumentCommand{\outputlist}{m}
{
\marinho_lists_output:n { #1 }
}
% define the internal functions
\cs_new_protected:Nn \__marinho_lists_check:n
{
% create the sequence if it doesn't exist
\seq_if_exist:cF { l_marinho_lists_#1_seq }
{
\seq_new:c { l_marinho_lists_#1_seq }
\int_new:c { l_marinho_lists_#1_int }
\int_incr:c { l_marinho_lists_#1_int }
}
}
\cs_new_protected:Nn \marinho_lists_add_restart:nn
{
\__marinho_lists_check:n { #1 }
% add the item in the form {<number>}{<text>}
\int_set:cn { l_marinho_lists_#1_int } { 1 }
\seq_put_right:cx { l_marinho_lists_#1_seq }
{
{ \int_eval:n { \int_use:c { l_marinho_lists_#1_int } } }
{ \exp_not:n { #2 } }
}
\int_incr:c { l_marinho_lists_#1_int }
}
\cs_new_protected:Nn \marinho_lists_add_continue:nn
{
\__marinho_lists_check:n { #1 }
% add the item in the form {<number>}{<text>}
\seq_put_right:cx { l_marinho_lists_#1_seq }
{% compute the number based on the sequence length
{ \int_eval:n { \int_use:c { l_marinho_lists_#1_int } } }
{ \exp_not:n { #2 } }
}
\int_incr:c { l_marinho_lists_#1_int }
}
\cs_new_protected:Nn \marinho_lists_output_format:n
{% the private function holds the format
\cs_set:Nn \__marinho_lists_output_current:nn { #1 }
}
\marinho_lists_output_format:n { #1~--~#2 \par } % a default
\cs_new_protected:Nn \marinho_lists_output:n
{% map the sequence using the current format
\seq_map_function:cN { l_marinho_lists_#1_seq } \__marinho_lists_item:n
}
\cs_new:Nn \__marinho_lists_item:n
{% \__marinho_lists_item:n receives an argument in the form {<number>}{<text>}
% which we pass to \__marinho_lists_output_current:nn as two arguments
\__marinho_lists_output_current:nn #1
}
\ExplSyntaxOff
\setlength{\parindent}{0pt} % just for this example
\begin{document}
\section{Fill in the lists}
This section will have no other output.
\addtolist{%
I wanted this whole sentence on this input, even with commas,
without breaking the sentence
}
\addtolist{If I don't use commas then it's ok}
\addtolist{This is in the general list}
\addtolist*{This will have number 1}
\addtolist{This will have number 2}
\section{Output the \texttt{general} list}
\listoutputformat{Input number #1 is: #2\par}
\outputlist{general}
\section{We can do in a \texttt{tabular}}
\listoutputformat{#1 & #2 \\}% for a table
\begin{tabular}{lp{6cm}}
\toprule
N & \multicolumn{1}{c}{Text} \\
\midrule
\outputlist{general}
\bottomrule
\end{tabular}
\end{document}
答案2
您发布的几乎所有代码都是通过逗号分隔列表实现的\cptdocommalist
,但我认为您的问题意味着您根本不想要这样,但也许
\documentclass{article}
\newcount\mycount
\newtoks\mylist
%odd name for this command? what is the "name" here?
\def\inputcommandname#1{%
\advance\mycount1
\mylist\expandafter{\the\expandafter\mylist
\expandafter\mydo\expandafter
{\the\mycount}{#1}}}
\def\commandnameoutputformat{\def\mydo##1##2}
\def\outputinnormalorder{\the\mylist}
\begin{document}
\inputcommandname{I wanted this whole sentence on this input, but when I use a comma it breaks the input and starts a new one}
\inputcommandname{If I don't use commas then it's ok}
\commandnameoutputformat{\par Input number #1 is: #2.\par}
Output:\par
\outputinnormalorder
\end{document}