在我从事线性代数和矩阵的工作中,我受到 LaTeX2 及其最多可传递给 9 个参数的\newcommand
限制。虽然 LaTeX3 对 也施加了同样的限制,但\NewDocumentCommand
我(非常兴奋地)注意到该xparse
包提供了许多可以解决此限制的参数处理器。特别是\SplitArgument
似乎正好提供了我需要的东西。遗憾的是,我无法从阅读文档中提取足够的信息来interface3
编写将使用 提取的数据并将它们放在我需要的位置的层\SplitArgument
。我希望下面的代码是不言自明的;它可以编译但由于显而易见的原因,它可以编译\myNinePerm
但不编译mynPerm
。我相信我的问题的答案不仅对我有很大的帮助,而且可以作为一个受欢迎的实际示例为所有 TeX 和 LaTeX3 新手提供帮助。
%document name: LaTeX3_xparse2.tex
%RN 16/3/2012
%COMMENTS:
% OBJECTIVE: Want to populate an nxn matrix by passing its elements separated by semicolons
% as a single argument rather than by passing them individually (which poses the restriction
% to 3 x 3 matrices since LaTeX3 imposes the same maximum number of arguments, 9, as does
% LaTeX2). LaTeX3 and one or other of the argument processors in xparse, for instance
% \SplitArgument will to the job, but once again, due to the lack of at least one concrete
% example, I cannot get the syntax right, especially for the internal function!
% APPROACH:
% (1) Have a simple function, call it \myNinePerm which displays a permutation of a 9-set
% as a 2 x 9 matrix with the top row showing the elements of the set in natural order and
% row 2 allowing the user to plug in their images under the mapping as individual arguments
% by passing the values as arguments(the LaTeX2 approach);
% (2) rewrite this same function by passing a single argument which contains the values
% separated by some token, for example a semi-colon. The restriction to nine elements is no
% longer relevant, but is maintained in order to avoid clouding the issue.
%==============================================================================================
\documentclass{article}
%\usepackage{expl3}
\usepackage{amsmath,xparse}
\ExplSyntaxOn
\NewDocumentCommand{\myNinePerm}{ m m m m m m m m m }
{
{\begin{pmatrix}
1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
#1 & #2 & #3 & #4 & #5 & #6 & #7 & #8 & #9
\end{pmatrix}}
}
\ExplSyntaxOff
\ExplSyntaxOn
\NewDocumentCommand{\mynPerm}{ m }
{ > { \SplitArgument { 8 } { ; } } m }
% assuming that the argument now contains nine values, how do I move these values to
% occupy the second row in the matrix below?
{
{\begin{pmatrix}
1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
% <val 1>&<val 2>&<val 3>&<val 4>&<val 5>&<val 6>&<val 7>&<val 8>&<val 9>
\end{pmatrix}}
}
\ExplSyntaxOff
\begin{document}
$\myNinePerm{9}{8}{7}{6}{5}{4}{3}{2}{1}$\\
$\mynPerm{{9;8;7;6;5;4;3;2;1}}$\\
\end{document}
答案1
\SplitArgument
和\SplitList
适用于非常基本的列表处理。当人们只需在项目之间插入一些内容时,事情会稍微复杂一些。
我提出了一个更简单的版本,它也可以处理任意数量的元素
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\perm}{ O{,} m } { \perm_build:nn { #1 } { #2 } }
%%% Here's the "real" code
\tl_new:N \l_perm_toprow_tl
\tl_new:N \l_perm_bottomrow_tl
\seq_new:N \l_perm_permutation_seq
\int_new:N \l_perm_numberofcols_int
\cs_new:Npn \perm_build:nn #1 #2
{
\group_begin:
\cs_set_eq:cN {c@MaxMatrixCols} \l_perm_numberofcols_int
\seq_set_split:Nnn \l_perm_permutation_seq { #1 } { #2 }
\int_set:Nn \l_perm_numberofcols_int { 1 }
\tl_set:Nn \l_perm_toprow_tl { 1 }
\seq_pop_left:NN \l_perm_permutation_seq \l_perm_bottomrow_tl
\seq_map_inline:Nn \l_perm_permutation_seq
{
\int_incr:N \l_perm_numberofcols_int
\tl_put_right:Nx \l_perm_toprow_tl { & \int_to_arabic:n { \l_perm_numberofcols_int } }
\tl_put_right:Nn \l_perm_bottomrow_tl { & ##1 }
}
\begin{pmatrix}
\tl_use:N \l_perm_toprow_tl \\
\tl_use:N \l_perm_bottomrow_tl
\end{pmatrix}
\group_end:
}
\ExplSyntaxOff
\begin{document}
$\perm{1,2,3,4,5,6,7,8,9}$
$\perm[;]{9;8;7;6;5;4;3;2;1;10;11;12}$
\end{document}
它使用一个序列在分离第一列后进行通常的映射。在映射的每个步骤中,我们将适当的元素添加到顶行和底行。
最后,我们设置了一个pmatrix
,但使用了一个技巧,即让\c@MaxMatrixCols
为\l_perm_numberofcols_int
,这样当请求的列数超过默认值 10 时,LaTeX 就不会发出声音。
怎么运行的
我们首先\perm
用一个可选值(默认值,
)和一个强制值来定义我们要构建的矩阵的第二行。这只是将控制权转移到“内部”版本\perm_build:nn
。
下一步是声明变量:两个用于存储行的标记列表、一个用于艰苦工作的序列和一个将执行两项服务的整数。
在一个组中,我们让 LaTeX 相信这是我们的整数变量(参见的\c@MaxMatrixCols
文档),然后我们使用可选参数来拆分强制参数并将信息片段存储在序列中。amsmath
MaxMatrixCols
\perm
然后我们在序列上开始递归,将整数变量初始化为 1,并将顶行包含“1”(这是必要的,以避免行分隔符&
太多)。因此,我们分离序列中最左边的元素(\seq_pop_left:NN
)初始化底行(感谢 Bruno Le Floch 提供的这个巧妙技巧)。
我们\seq_map_inline:Nn
进行递归:对于序列的每个元素,我们将 前面的整数变量的值(刚刚增加的)添加到顶行&
;类似地,我们将其添加到底行&
,后面跟着序列中的当前项(用 表示##1
)。
最后,我们设置矩阵并关闭组,因此保持MaxMatrixCols
不变,并且在工作期间不受列数的限制。
通过使用函数,可以将其推广到在顶行中具有任意元素序列\seq_mapthread_function:NNN
。
答案2
我想尝试回答您的问题并提供一种方法。
首先一个小提示:提供的命令xparse
不需要用ExplSyntaxOn
...括起来。ExplSyntaxOff
在上述方法中,函数\mynPerm
定义有一个可选参数和一个强制参数。语法如下:
\mynPerm[<separator>]{<list>}
默认分隔符为;
。输入参数不受限制。矩阵的第一列由强制输入的参数数量计算得出。
输入以下几行
\mynPerm{9;8;7;6;5;4;3;2;1}
\mynPerm{13;15;15,65;19}
\mynPerm[,]{13;15;15,65;19}
结果为:
\documentclass{article}
%\usepackage{expl3}
\usepackage{amsmath,xparse}
\NewDocumentCommand{\myNinePerm}{ m m m m m m m m m }
{%
\ensuremath{%
\begin{pmatrix}%
1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
#1 & #2 & #3 & #4 & #5 & #6 & #7 & #8 & #9
\end{pmatrix}%
}%
}
%
\ExplSyntaxOn
\seq_new:N \l_perm_store_seq
\seq_new:N \l_perm_tmpa_seq
\cs_generate_variant:Nn \seq_set_eq:NN {Nn}
\tl_new:N \l_perm_first_column_tl
\tl_new:N \l_perm_second_column_tl
\NewDocumentCommand \mynPerm { O{;} m }
{
\seq_clear:N \l_perm_store_seq
\seq_set_split:Nnn \l_perm_store_seq { #1 } { #2 }
\seq_mynPerm_set_first_column:N \l_perm_store_seq
\seq_mynPerm_set_second_column:N \l_perm_store_seq
\seq_mynPerm_output_matrix:NN \l_perm_first_column_tl \l_perm_second_column_tl
}
\cs_new:Npn \seq_mynPerm_set_first_column:N #1
{
\seq_set_eq:NN \l_perm_tmpa_seq #1
\int_set_eq:NN \l_tmpa_int \c_two
\tl_set:Nx \l_perm_first_column_tl { 1 & }
\int_while_do:nNnn { \l_tmpa_int } < { \seq_length:N \l_perm_tmpa_seq }
{
\tl_put_right:NV \l_perm_first_column_tl { \l_tmpa_int & }
\int_incr:N \l_tmpa_int
}
\tl_put_right:NV \l_perm_first_column_tl { \l_tmpa_int }
% \tl_to_str:N \l_perm_first_column_tl
}
\cs_new:Npn \seq_mynPerm_set_second_column:N #1
{
\seq_set_eq:NN \l_perm_tmpa_seq #1
\tl_clear:N \l_perm_second_column_tl
\seq_map_inline:Nn \l_perm_tmpa_seq
{
\tl_put_right:Nn \l_perm_second_column_tl { ##1 & }
}
\tl_reverse:N \l_perm_second_column_tl
\tl_remove_once:Nn \l_perm_second_column_tl { & }
\tl_reverse:N \l_perm_second_column_tl
% \tl_to_str:N \l_perm_second_column_tl
}
\cs_new:Npn \seq_mynPerm_output_matrix:NN #1 #2
{
\group_begin:
\tl_set_eq:NN \l_tmpa_tl #1
\tl_set_eq:NN \l_tmpb_tl #2
\int_set:cn {c@MaxMatrixCols} { \tl_length:N \l_tmpa_tl }
\ensuremath{%
\begin{pmatrix}%
\tl_use:N \l_tmpa_tl \\
\tl_use:N \l_tmpb_tl
\end{pmatrix}%
}%
\group_end:
}
\ExplSyntaxOff
\begin{document}
\myNinePerm{9}{8}{7}{6}{5}{4}{3}{2}{1}
\mynPerm{9;8;7;6;5;4;3;2;1}
\mynPerm{13;15;15,65;19}
\mynPerm[,]{13;15;15,65;19}
\end{document}