我正在为 REST API 编写文档。因此有很多信息需要重复。所以我试图弄清楚几件事:
考虑以下代码:
\newcommand\insertitem[1]{\item \texttt{#1}} \NewDocumentCommand{\listfields}{ >{ \SplitList {,} } m } { \paragraph{General available fields:} \begin{itemize} \ProcessList{#1}{ \insertitem } \end{itemize} } % works: \listfields{a,b,c,d,e} % doesn't work: \def \fields {a,b,c,d,e} \listfields{\fields}
它将整个集合作为单个字符串返回,因此不会对其进行迭代。为什么?或者:我该如何让它工作?
为了使文档更易于维护,我想设置 3 个变量并以不同的方式使用它。首先是 3 个变量:
% route \def \route {/myRestRoute} % fields \def \fields {a,b,c,d,e} % field descriptions \def \fielddesc { description for a, description for b, description for c, description for d, description for e }
现在(如果问题1.得到解决),我想做以下事情:输出
\field
和的元组\fielddesc
。为此我必须同时处理两个列表。结果应该如下所示:\texttt{a} - description for a \texttt{b} - description for b \texttt{c} - description for c \texttt{d} - description for d \texttt{e} - description for e
最后但并非最不重要的一点是,我需要从
\fields
变量中获取 2 个值并将其用作函数的参数。我需要以某种方式指定它应该采用哪 2 个值。默认情况下,值 2 和 3 是可以的,但有时我可能必须使用值 1 和 4(目前不存在此例外,但做好准备总是更好的):\newcommand{\arf}[2] { #1, #2 } % and call it using something like this: \arf{\fields[1]}{\fields[2]} % where [1] and [2] should be indices of the comma separated fields array.
答案1
你想要的通常不是仅靠 就可以实现的xparse
。传递显式列表或控制序列的主要问题是对参数进行扩展,如果列表是显式的并且第一个项是一个控制序列或者无论如何以一开始。
因此,最好将这两种情况分开,我建议使用如下语法
\listfields*{a,b,c,d,e}
\listfields{\fields}
因此*
宣布一个显式列表。添加一个可选参数来更改分隔符也相当容易,您将在示例代码中看到它的实际作用。因此您可以这样做
\listfields*[;]{a;b;c;d;e}
\listfields[;]{\fieldssemicolon} % \fieldssemicolon has ; as separator
\listdescriptions{\fields}{\fieldsdesc}
\listdescriptions[;]{\fieldssemicolon}{\fielddescsemicolon} % both use ;
\listdescription[;][,]{\fieldssemicolon}{\fieldsdesc}
\listdescription[,][;]{\fields}{\fielddescsemicolon}
对于“双重映射”,我假设字段和描述都存储在宏中,并且\arf
使用语法
\arf{\fields}{2,3}
\arf[;]{\fieldssemicolon}{1,2}
这个例子
\documentclass{article}
\usepackage{xparse}
\newcommand\insertitem[1]{\item \texttt{#1}}
\ExplSyntaxOn
\NewDocumentCommand{\listfields}{sO{,}m}
{
\paragraph{General~available~fields:}
\begin{itemize}
\IfBooleanTF{#1}
{\benj_listfields:nn {#2}{#3}}
{\benj_listfields:no {#2}{#3}}
\end{itemize}
}
\cs_new_protected:Npn \benj_listfields:nn #1 #2
{
\seq_set_split:Nnn \l_benj_fields_seq { #1 } { #2 }
\seq_map_inline:Nn \l_benj_fields_seq { \insertitem{##1} }
}
\cs_generate_variant:Nn \benj_listfields:nn { no }
\NewDocumentCommand{\listdescriptions}{O{,}omm}
{
\paragraph{General~available~fields~with~descriptions:}
\begin{itemize}
\IfNoValueTF{#2}
{\benj_list_descriptions:nnNN {#1} {#1} #3 #4}
{\benj_list_descriptions:nnNN {#1} {#2} #3 #4}
\end{itemize}
}
\cs_new_protected:Npn \benj_list_descriptions:nnNN #1 #2 #3 #4
{
\seq_set_split:NnV \l_benj_fields_seq { #1 } #3
\seq_set_split:NnV \l_benj_descriptions_seq { #2 } #4
\seq_mapthread_function:NNN
\l_benj_fields_seq
\l_benj_descriptions_seq
\benj_make_description:nn
}
\cs_new_protected:Npn \benj_make_description:nn #1 #2
{
\item \texttt{#1},~#2
}
\NewDocumentCommand{\arf}{O{,}mm}
{% #1 (optional) = separator, #2 = list macro, #3 = list of items
\benj_arf:nNn {#1} #2 {#3}
}
\cs_new_protected:Npn \benj_arf:nNn #1 #2 #3
{
\paragraph{Some~fields:}
\begin{itemize}
\seq_set_split:NnV \l_benj_fields_seq { #1 } { #2 }
\clist_map_inline:nn { #3 } { \item \seq_item:Nn \l_benj_fields_seq { ##1 } }
\end{itemize}
}
\seq_new:N \l_benj_fields_seq
\seq_new:N \l_benj_descriptions_seq
\ExplSyntaxOff
\begin{document}
\section{List fields}
\listfields*{a,b,c,d,e}
\def \fields {a,b,c,d,e}
\listfields{\fields}
\def\fieldssemicolon{a;b;c;d;e}
\listfields[;]{\fieldssemicolon}
\newpage
\section{List fields with descriptions}
\def \fielddesc
{
description for a,
description for b,
description for c,
description for d,
description for e
}
\def\fielddescsemicolon
{
description for a;
description for b;
description for c;
description for d;
description for e
}
\listdescriptions{\fields}{\fielddesc}
\listdescriptions[;][,]{\fieldssemicolon}{\fielddesc}
\listdescriptions[;]{\fieldssemicolon}{\fielddescsemicolon}
\newpage
\section{Extract fields}
\arf{\fields}{2,3}
\arf{\fields}{1,3,5}
\arf[;]{\fieldssemicolon}{2,4}
\end{document}