我正在开发一个宏,将来它可以为我节省很多时间。目前,我想要的一个命令已经运行,但第二部分运行起来却遇到了麻烦。第一个命令定义如下:
\NewDocumentCommand\x
{
s
>{\SplitList{,}}o
>{\SplitList{,}}o
>{\SplitList{,}}o
>{\SplitList{,}}o
>{\SplitList{,}}o
>{\SplitList{,}}o
>{\SplitList{,}}o
>{\SplitList{,}}o
}{
% Full definition of the command
}
此命令需要八个可选参数,每个参数都是一个逗号分隔的列表,通常是数字,但这不是必需的。我可能会称之为\x[-3,0][0,-2]
或\x[1,2,3,0][4,5,6,0][7,8,9,0]
。每个列表的长度始终相同。
我正在尝试创建第二个命令,它的作用有点像转置。因此它也需要最多八个列表,但这些列表用星号分隔,元素是命令中的列表\x
。用一个例子来展示它是如何工作的是最容易的:
\mxm
[ [3,2]*[-3, 0]*[ 1,-2] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
相当于:
\x[3,2][1,1]
\x[-3,0][0,-2]
\x[1,-2][-1,3]
这些星型列表中的每一个都具有相同数量的元素。如果它们具有不同数量的元素或不是命令参数的元素,\x
则可能会发生任何事情,错误、插入某种空元素、截断为最短列表等。它不会以这种方式调用,所以没关系。
这些列表的长度就是\x
有多少个调用。在这个例子中,长度是 3,所以有 3 个调用,\x
但如果长度更长或更短,则数量会有所不同。列表的数量是每次调用 有多少个参数\x
。在这个例子中,有两个,但最多可以有 8 个。
如果可能的话,我希望能够将星星从 传递给\mxm*
,\x*
但如果这太难,那么我有一个替代解决方案,因为它不应该经常出现。如下所示:
\mxm[[1,3,1]*[-1, 0,3]]
[[2,2,1]*[ 0,-2,2]]
[[3,1,2]*[ 1,-2,1]]
相当于:
\x*[1,3,1]
[2,2,1]
[3,1,2]
\x*[-1, 0,3]
[ 0,-2,2]
[ 1,-2,1]
这是 MWE举个例子\x
(只是占位符,可能不叫\x
)。它还包含了我取得的进展,尽管我无法想象它有多大帮助。
答案1
尾递归,即再次调用自身的宏以及事先进行大量的参数交换,可能会起到作用。;-)
如果我理解正确的话,\mxm
就是处理一个可选参数列表,其中每个可选参数本身都包含一个*
以 - 分隔的可选参数列表。
您没有指定如果不是所有*
可选参数分隔列表都包含相同数量的元素的话该怎么办。
因此,我可以自由地实施一些事情,以便在由于列表长度不同或参数指定为空而导致缺少 - 分隔元素的[NULL]
地方提供这些元素。*
*
\documentclass{article}
\usepackage{xparse}
\makeatletter
%%=============================================================================
%% Little helpers:
%%.............................................................................
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\z@\@secondoftwo}%
{\expandafter\z@\@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%.............................................................................
%% \romannumeral\UD@ExtractFirstArgLoop{<argument>\UD@SelDOm}%
%% yields <argument>'s 1st undelimited argument.
%% <argument> must not be blank, i.e., must neither be empty nor consist
%% only of explicit character tokens of catcode 10 and charcode 32.
%%
%% \UD@SelDOm must not be defined in terms of \outer !
%%.............................................................................
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
{\expandafter\z@\@secondoftwo{}#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% \mxm starts a loop for collecting an arbitrary amount of optional arguments.
%%.............................................................................
\NewDocumentCommand\mxm{}{\innermxm{}}%
%%-----------------------------------------------------------------------------
%% \innermxm checks if another optional argument is present.
%% If so it will be collected and \innermxm is called again.
%% Otherwise the loop for forming the calls to \x is started.
%%.............................................................................
\NewDocumentCommand\innermxm{m >{\SplitList{*}}o}{%
% #1 - list of brace-nested optional arguments collected so far.
% #2 - either the no-value-marker or the next optional argument:
\IfNoValueTF{#2}{%
% Start the loop for forming the calls to \x/for re-arranging things:
% \romannumeral is not really needed here, but while writing
% this I wanted the missing-number-error in case of messing up
% the tail-recursive \mxmloop's flipping-around/exchanging
% of arguments. ;-)
\romannumeral\mxmloop{\x}{}{}{#1}{}%
}{%
% Add the current optional argument to the list #1 and check if
% another optional argument is present...
\innermxm{#1{#2}}%
}%
}%
\newcommand\mxmloop[5]{%
%#1 - token-list produced so far forming current new call to \x
%#2 - new list of lists
%#3 - indicator if all elements of current list of lists were empty.
%#4 - current list of lists
%#5 - list of calls to \x
\UD@CheckWhetherNull{#4}{%
\UD@CheckWhetherNull{#3}{%
\z@#5% <- this \z@ terminates the (actually not needed)
% \romannumeral-expansion started by \innermxm.
% It denotes a non-positive number and therefore
% gets removed silently.
}{%
\mxmloop{\x}{}{}{#2}{#5#1}%
}%
}{%
\UD@PassFirstToSecond{#5}{%
\expandafter\UD@PassFirstToSecond\expandafter{\@firstoftwo{}#4}{%
\expandafter\UD@CheckWhetherNull\expandafter{\romannumeral\UD@ExtractFirstArgLoop{#4\UD@SelDOm}}{%
\UD@PassFirstToSecond{#3}{%
\UD@PassFirstToSecond{#2{}}{%
\UD@PassFirstToSecond{#1[NULL]}{\mxmloop}%
}%
}%
}{%
\UD@PassFirstToSecond{m}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral
\expandafter\expandafter\expandafter\UD@PassFirstToSecond
\expandafter\expandafter\expandafter{%
\expandafter\@firstoftwo\expandafter{\expandafter}%
\romannumeral\UD@ExtractFirstArgLoop{#4\UD@SelDOm}}{\z@#2}%
}{%
\expandafter\UD@CheckWhetherNull\expandafter{%
\romannumeral\expandafter
\UD@ExtractFirstArgLoop\expandafter{%
\romannumeral\UD@ExtractFirstArgLoop{#4\UD@SelDOm}%
\UD@SelDOm}%
}{%
\UD@PassFirstToSecond{#1[NULL]}{\mxmloop}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral
\expandafter\UD@Exchange\expandafter{%
\romannumeral\expandafter
\UD@ExtractFirstArgLoop\expandafter{%
\romannumeral\UD@ExtractFirstArgLoop{#4\UD@SelDOm}%
\UD@SelDOm}%
}{\z@#1}%
}{\mxmloop}%
}%
}%
}%
}%
}%
}%
}%
}%
%%=============================================================================
% Let's define \x to collect an arbitrary amount of optional arguments and to display them:
\NewDocumentCommand\x{}{\innerx{}}%
\NewDocumentCommand\innerx{mo}{%
\IfNoValueTF{#2}{\par\noindent\texttt{\detokenize\expandafter{\string\x#1}}}{\innerx{#1[#2]}}%
}%
\makeatother
\begin{document}
\footnotesize
\noindent Test 1:
\mxm
[ [3,2]*[-3, 0]*[ 1,-2] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
[ [3,5]*[ 6,-7]*[-8, 9] ]
\bigskip\hrule\bigskip
\noindent Test 2:
\mxm
[ [3,2]*[-3, 0] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
[ [3,5]*[ 6,-7]*[-8, 9] ]
\bigskip\hrule\bigskip
\noindent Test 3:
\mxm
[ [3,2]*[-3, 0]*[ 1,-2]*[2,8] ]
[ [1,1]*[ 0,-2]* * ]
[ [3,5]*[ 6,-7]*[-8, 9]* ]
\bigskip\hrule\bigskip
\noindent Test 4:
\mxm
[ [1,1]*[ 0,-2]]
[ [3,2]*[-3, 0]*[ 1,-2]*[2,8]*[17,4] ]
[ [3,5]*[ 6,-7]*[-8, 9]* ]
\bigskip\hrule\bigskip
\noindent Test 5:
\mxm
[ [3,2]*[-3, 0]*[ 1,-2]*[2,8] ]
[ ]
[ [3,5]*[ 6,-7]*[-8, 9]* ]
\bigskip\hrule\bigskip
\noindent Test 6:
\mxm
[ [3,2]*[-3, 0] ]
[ [1,1]*[ 0,-2] ]
[ [3,5]*[ 6,-7] ]
[ [2,7]*[ 7,-0] ]
[ [8,4]*[ 6,-0] ]
\bigskip\hrule\bigskip
\noindent Test 7:
\mxm
[ [3,2]*[-3, 0]*[1,1]*[ 0,-2]*[3,5]*[ 6,-7] ]
\bigskip\hrule\bigskip
\noindent Test 8:
\mxm
[ [3,2] ]
\bigskip\hrule\bigskip
\noindent Test 9:
\mxm
[ ]
\bigskip\hrule\bigskip
\noindent Test 10:
\mxm
\noindent bla
\end{document}
其变体可用于创建矩阵:
\documentclass{article}
\usepackage{xparse}
\usepackage{amsmath}
\makeatletter
%%=============================================================================
%% Little helpers:
%%.............................................................................
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\z@\@secondoftwo}%
{\expandafter\z@\@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%.............................................................................
%% \romannumeral\UD@ExtractFirstArgLoop{<argument>\UD@SelDOm}%
%% yields <argument>'s 1st undlimited argument.
%% <argument> must not be blank, i.e., must neither be empty nor consist
%% only of explicit character tokens of catcode 10 and charcode 32.
%%
%% \UD@SelDOm must not be defined in terms of \outer !
%%.............................................................................
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
{\expandafter\z@\@secondoftwo{}#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% \mxm starts a loop for collecting an arbitrary amount of optional arguments.
%%.............................................................................
\NewDocumentCommand\mxm{s}{%
\IfBooleanTF{#1}{\innermxm{\x*}{}}{\innermxm{\x}{}}%
}%
%%-----------------------------------------------------------------------------
%% \innermxm checks if another optional argument is present.
%% If so it will be collected and \innermxm is called again.
%% Otherwise the loop for forming the calls to \x is started.
%%.............................................................................
\NewDocumentCommand\innermxm{mm >{\SplitList{*}}o}{%
% #1 - command for creating matrices
% #2 - list of brace-nested optional arguments collected so far.
% #3 - either the no-value-marker or the next optional argument:
\IfNoValueTF{#3}{%
% Start the loop for forming the calls to \x/for re-arranging things:
% \romannumeral is not really needed here, but while writing
% this I wanted the missing-number-error in case of messing up
% the tail-recursive \mxmloop's flipping-around/exchanging
% of arguments. ;-)
\romannumeral\mxmloop{#1}{}{}{}{#2}{}%
}{%
% Add the current optional argument to the list #2 and check if
% another optional argument is present...
\innermxm{#1}{#2{#3}}%
}%
}%
\newcommand\mxmloop[6]{%
%#1 - command for creating matrices
%#2 - token-list produced so far forming current command for creating matrices
%#3 - new list of lists
%#4 - indicator if all elements of current list of lists were empty.
%#5 - current list of lists
%#6 - list of calls for creating matrices
\UD@CheckWhetherNull{#5}{%
\UD@CheckWhetherNull{#4}{%
\z@#6% <- this \z@ terminates the (actually not needed)
% \romannumeral-expansion started by \innermxm.
% It denotes a non-positive number and therefore
% gets removed silently.
}{%
\mxmloop{#1}{}{}{}{#3}{#6#1#2}%
}%
}{%
\UD@PassFirstToSecond{#6}{%
\expandafter\UD@PassFirstToSecond\expandafter{\@firstoftwo{}#5}{%
\expandafter\UD@CheckWhetherNull\expandafter{\romannumeral\UD@ExtractFirstArgLoop{#5\UD@SelDOm}}{%
\UD@PassFirstToSecond{#4}{%
\UD@PassFirstToSecond{#3{}}{%
\UD@PassFirstToSecond{#2%[NULL]
}{\mxmloop{#1}}%
}%
}%
}{%
\UD@PassFirstToSecond{m}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral
\expandafter\expandafter\expandafter\UD@PassFirstToSecond
\expandafter\expandafter\expandafter{%
\expandafter\@firstoftwo\expandafter{\expandafter}%
\romannumeral\UD@ExtractFirstArgLoop{#5\UD@SelDOm}}{\z@#3}%
}{%
\expandafter\UD@CheckWhetherNull\expandafter{%
\romannumeral\expandafter
\UD@ExtractFirstArgLoop\expandafter{%
\romannumeral\UD@ExtractFirstArgLoop{#5\UD@SelDOm}%
\UD@SelDOm}%
}{%
\UD@PassFirstToSecond{#2%[NULL]
}{\mxmloop{#1}}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral
\expandafter\UD@Exchange\expandafter{%
\romannumeral\expandafter
\UD@ExtractFirstArgLoop\expandafter{%
\romannumeral\UD@ExtractFirstArgLoop{#5\UD@SelDOm}%
\UD@SelDOm}%
}{\z@#2}%
}{\mxmloop{#1}}%
}%
}%
}%
}%
}%
}%
}%
}%
%%=============================================================================
% Let's define \x to collect an arbitrary amount of optional arguments and to create a matrix of them:
\NewDocumentCommand\x{s}{%
\IfBooleanTF{#1}{\innerx{}{}{pmatrix}}{\innerx{}{}{bmatrix}}%
}%
\NewDocumentCommand\innerx{mmm >{\SplitList{,}}o}{%
% #1 - matrix-content created so far
% #2 - things to prepend to matrix-row to create (empty with 1st row, \\ otherwise)
% #3 - name of matrix-environment
% #4 - optional argument from which next matrix-row is to be created
\IfNoValueTF{#4}%
{\UD@CheckWhetherNull{#1}{}{\begin{#3}#1\end{#3}}}%
{%
\expandafter\innerx
\expandafter{\romannumeral\expandafter\UD@Exchange\expandafter{\romannumeral\intersperseloop{#4}{}{}}{\z@#1#2}}%
{\\}%
{#3}%
}%
}%
\newcommand\intersperseloop[3]{%
%#1 - argument list
%#2 - interspersed list
%#3 - token to prepend (empty with 1st element, & otherwise)
\UD@CheckWhetherNull{#1}{\z@#2}{%
\UD@PassFirstToSecond{&}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral\expandafter\UD@Exchange\expandafter{\romannumeral\UD@ExtractFirstArgLoop{#1\UD@SelDOm}}{\z@#2#3}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\@firstoftwo{}#1}{%
\intersperseloop
}%
}%
}%
}%
}%
\makeatother
\begin{document}
\footnotesize
\noindent Test 1:
$$\mxm
[ [3,2]*[-3, 0]*[ 1,-2] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
[ [3,5]*[ 6,-7]*[-8, 9] ]$$
\bigskip\hrule\bigskip
\noindent Test 2:
$$\mxm*
[ [3,2]*[-3, 0] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
[ [3,5]*[ 6,-7]*[-8, 9] ]$$
\bigskip\hrule\bigskip
\noindent Test 2a:
$$\mxm
[ [3,2]* *[-3, 0] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
[ [3,5]*[ 6,-7]*[-8, 9] ]$$
\bigskip\hrule\bigskip
\noindent Test 3:
$$\mxm
[ [3,2] * [-3, 0] * [ 1,-2] * [2,8] ]
[ [1,1] * [ 0,-2] * * ]
[ [3,5] * [ 6,-7] * [-8, 9] * ]$$
\bigskip\hrule\bigskip
\noindent Test 4:
$$\mxm
[ [1,1]*[ 0,-2]]
[ [3,2]*[-3, 0]*[ 1,-2]*[2,8]*[17,4] ]
[ [3,5]*[ 6,-7]*[-8, 9]* ]$$
\bigskip\hrule\bigskip
\noindent Test 5:
$$\mxm
[ [3,2]*[-3, 0]*[ 1,-2]*[2,8] ]
[ ]
[ [3,5]*[ 6,-7]*[-8, 9]* ]$$
\bigskip\hrule\bigskip
\noindent Test 6:
$$\mxm*
[ [3,2]*[-3, 0] ]
[ [1,1]*[ 0,-2] ]
[ [3,5]*[ 6,-7] ]
[ [2,7]*[ 7,-0] ]
[ [8,4]*[ 6,-0] ]
[ [3,2]*[-3, 0] ]
[ [1,1]*[ 0,-2] ]
[ [3,5]*[ 6,-7] ]
[ [2,7]*[ 7,-0] ]
[ [8,4]*[ 6,-0] ]
[ [3,2]*[-3, 0] ]
[ [1,1]*[ 0,-2] ]
[ [3,5]*[ 6,-7] ]
[ [2,7]*[ 7,-0] ]
[ [8,4]*[ 6,-0] ]$$
\bigskip\hrule\bigskip
\noindent Test 6b:
$$\mxm
[ [3,2] * [-3, 0] * ]
[ [1,1] * * [ 0,-2] ]
[ [3,5] * * [ 6,-7] ]
[ [2,7] * * [ 7,-0] ]
[ [8,4] * * [ 6,-0] ]
[ * * [ 6,-0] ]$$
\bigskip\hrule\bigskip
\noindent Test 7:
$$\mxm
[ [3,2]*[-3, 0]*[1,1]*[ 0,-2]*[3,5]*[ 6,-7] ]$$
\bigskip\hrule\bigskip
\noindent Test 8:
$$\mxm
[ [3,2] ]$$
\bigskip\hrule\bigskip
\noindent Test 9:
$$\mxm
[ ]$$
\bigskip\hrule\bigskip
\noindent Test 10:
$$\mxm$$
\noindent bla
\end{document}
答案2
如果你想创建一个\mxm
:
\mxm
[ [3,2]*[-3, 0]*[ 1,-2] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
去做
\x[3,2][1,1]
\x[-3,0][0,-2]
\x[1,-2][-1,3]
然后你可以定义
\def\mxm [ [#1]*[#2]*[#3] ] [ [#4]*[#5]*[#6] ]{%
\x[#1][#4]
\x[#2][#5]
\x[#3][#6]
}
编辑:如果我理解你的需求,那么你需要转置参数。当\mxm
给定任意行和列时,你需要转换
\mxm
[ [A1]*[A2]*[A3]*[A4] ]
[ [B1]*[B2]*[B3]*[B4] ]
[ [C1]*[C2]*[C3]*[C4] ]
进入一系列调用:
\x[A1][B1][C1]
\x[A2][B2][C2]
\x[A3][B3][C3]
\x[A4][B4][C4]
你可以测试以下代码:
\newcount\numrows \newcount\tmpnum
\def\mxm {\numrows=0 \mxmA}
\def\mxmA [ #1 ] {\advance\numrows by1 \sdef{r:\the\numrows}{#1}%
\futurelet\next\mxmB}
\def\mxmB {\ifx\next[\expandafter\mxmA \else \expandafter \mxmC\fi}
\def\mxmC {\expandafter\ifx \csname r:1\endcsname \empty \else
\tmpnum=0 \def\xparams{}%
\loop
\advance\tmpnum by1
\expandafter \expandafter \expandafter \mxmD
\csname r:\the\tmpnum\endcsname \end
\ifnum\tmpnum<\numrows \repeat
\expandafter \x \xparams \relax
\expandafter \mxmC \fi
}
\def\mxmD #1[#2]#3\end{\sdef{r:\the\tmpnum}{#3}\addto\xparams{[#2]}}
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\sdef#1{\expandafter\def\csname#1\endcsname}
% Just for testing:
\def\x #1\relax{\message{running \string\x #1}}
\mxm
[ [A1]*[A2]*[A3]*[A4] ]
[ [B1]*[B2]*[B3]*[B4] ]
[ [C1]*[C2]*[C3]*[C4] ]
\bye
此代码(之后)的消息结果\pdftex testfile
为:
running \x[A1][B1][C1] running \x[A2][B2][C2]
running \x[A3][B3][C3] running \x[A4][B4][C4]
答案3
我不认为这是个好方法,特别是在八个可选参数中。但顾客永远是对的。
\documentclass{article}
\usepackage{amsmath}
\ExplSyntaxOn
\NewDocumentCommand\makematrix{ s o o o o o o o o }
{
\begin{ \IfBooleanTF { #1 } { p } { b } matrix }
\bryce_make_matrix:nnnnnnnn { #2 } { #3 } { #4 } { #5 } { #6 } { #7 } { #8 } { #9 }
\end{ \IfBooleanTF { #1 } { p } { b } matrix }
}
\NewDocumentCommand{\mxm} { s o o o o o o o o }
{
\group_begin: % localize the setting of the sequences
\IfValueT{#2}
{
\seq_set_split:Nnn \l__bryce_mxm_i_seq { * } { #2 }
}
\IfValueT{#3}
{
\seq_set_split:Nnn \l__bryce_mxm_ii_seq { * } { #3 }
}
\IfValueT{#4}
{
\seq_set_split:Nnn \l__bryce_mxm_iii_seq { * } { #4 }
}
\IfValueT{#5}
{
\seq_set_split:Nnn \l__bryce_mxm_iv_seq { * } { #5 }
}
\IfValueT{#6}
{
\seq_set_split:Nnn \l__bryce_mxm_v_seq { * } { #6 }
}
\IfValueT{#7}
{
\seq_set_split:Nnn \l__bryce_mxm_vi_seq { * } { #7 }
}
\IfValueT{#8}
{
\seq_set_split:Nnn \l__bryce_mxm_vii_seq { * } { #8 }
}
\IfValueT{#9}
{
\seq_set_split:Nnn \l__bryce_mxm_viii_seq { * } { #9 }
}
\cs_set_protected:Nx \__bryce_mxm:
{
\makematrix \IfBooleanT { #1 } { * }
}
\__bryce_mxm_do:
\group_end:
}
\cs_new_protected:Nn \bryce_make_matrix:nnnnnnnn
{
\tl_if_novalue:nF { #1 } { \__bryce_make_row:n { #1 } }
\tl_if_novalue:nF { #2 } { \__bryce_make_row:n { #2 } }
\tl_if_novalue:nF { #3 } { \__bryce_make_row:n { #3 } }
\tl_if_novalue:nF { #4 } { \__bryce_make_row:n { #4 } }
\tl_if_novalue:nF { #5 } { \__bryce_make_row:n { #5 } }
\tl_if_novalue:nF { #6 } { \__bryce_make_row:n { #6 } }
\tl_if_novalue:nF { #7 } { \__bryce_make_row:n { #7 } }
\tl_if_novalue:nF { #8 } { \__bryce_make_row:n { #8 } }
}
\cs_new_protected:Nn \__bryce_make_row:n
{
\clist_set:Nn \l__bryce_row_clist { #1 }
\clist_use:Nn \l__bryce_row_clist { & }
\\
}
\seq_new:N \l__bryce_mxm_i_seq
\seq_new:N \l__bryce_mxm_ii_seq
\seq_new:N \l__bryce_mxm_iii_seq
\seq_new:N \l__bryce_mxm_iv_seq
\seq_new:N \l__bryce_mxm_v_seq
\seq_new:N \l__bryce_mxm_vi_seq
\seq_new:N \l__bryce_mxm_vii_seq
\seq_new:N \l__bryce_mxm_viii_seq
\int_new:N \l__bryce_mxm_int
\cs_new_protected:Nn \__bryce_mxm_do:
{
\int_step_inline:nn { \seq_count:N \l__bryce_mxm_i_seq }
{
\int_set:Nn \l__bryce_mxm_int { ##1 }
\exp_last_unbraced:Ne \__bryce_mxm: \__bryce_mxm_args:
}
}
\cs_new:Nn \__bryce_mxm_args:
{
\int_step_function:nN { 8 } \__bryce_mxm_args_aux:n
}
\cs_new:Nn \__bryce_mxm_args_aux:n
{
\seq_item:cn { l__bryce_mxm_\int_to_roman:n { #1 }_seq } { \l__bryce_mxm_int }
}
\ExplSyntaxOff
\begin{document}
\[
\makematrix[3,2][1,1]
\makematrix[-3, 0][ 0,-2]
\makematrix[ 1,-2][-1, 3]
\]
\[
\mxm
[ [3,2]*[-3, 0]*[ 1,-2] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
\]
\[
\makematrix*[3,2][1,1]
\makematrix*[-3, 0][ 0,-2]
\makematrix*[ 1,-2][-1, 3]
\]
\[
\mxm*
[ [3,2]*[-3, 0]*[ 1,-2] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
\]
\end{document}
答案4
如果您不介意使用一些支架,事情就会变得容易得多。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{amsmath}
\ExplSyntaxOn
\tl_new:N \l_doc_tmpa_tl
\tl_new:N \l_doc_tmpb_tl
\tl_new:N \l_doc_tmpc_tl
\int_new:N \l_doc_tmpa_int
\int_new:N \l_doc_tmpb_int
\int_new:N \l_doc_tmpc_int
\clist_new:N \l_doc_tmpa_clist
\seq_new:N \l_doc_tmpa_seq
\seq_new:N \l_doc_tmpb_seq
\seq_new:N \l_doc_tmpc_seq
\seq_new:N \l_doc_tmpd_seq
\seq_new:N \l_doc_tmpe_seq
\cs_set:Npn \doc_extract_square_bracket:nN #1#2 {
\tl_set:Nn \l_doc_tmpa_tl {#1}
\seq_clear:N #2
\int_set:Nn \l_doc_tmpa_int {0}
\tl_clear:N \l_doc_tmpc_tl
\bool_do_until:nn {\tl_if_empty_p:N \l_doc_tmpa_tl} {
\tl_set:Nx \l_doc_tmpb_tl {\tl_head:N \l_doc_tmpa_tl}
\tl_set:Nx \l_doc_tmpa_tl {\tl_tail:N \l_doc_tmpa_tl}
\exp_args:NV \str_case:nnF \l_doc_tmpb_tl {
{[} {
\int_compare:nNnT {\l_doc_tmpa_int} > {0} {
\tl_put_right:NV \l_doc_tmpc_tl \l_doc_tmpb_tl
}
\int_incr:N \l_doc_tmpa_int
}
{]} {
\int_decr:N \l_doc_tmpa_int
\int_compare:nNnTF {\l_doc_tmpa_int} > {0} {
\tl_put_right:NV \l_doc_tmpc_tl \l_doc_tmpb_tl
}{
\seq_put_right:NV #2 \l_doc_tmpc_tl
\tl_clear:N \l_doc_tmpc_tl
}
}
} {
\int_compare:nNnT {\l_doc_tmpa_int} > {0} {
\tl_put_right:NV \l_doc_tmpc_tl \l_doc_tmpb_tl
}
}
}
}
\newcommand{\x}[1]{
\seq_clear:N \l_doc_tmpc_seq
\doc_extract_square_bracket:nN {#1} \l_doc_tmpb_seq
\seq_map_variable:NNn \l_doc_tmpb_seq \l_doc_tmpa_tl {
\clist_set:NV \l_doc_tmpa_clist \l_doc_tmpa_tl
\seq_put_right:Nx \l_doc_tmpc_seq {\clist_use:Nn \l_doc_tmpa_clist {\c_alignment_token}}
}
\begin{bmatrix}
\seq_use:Nn \l_doc_tmpc_seq {\\}
\end{bmatrix}
}
\cs_set:Npn \doc_temp_seq_name:n #1 {
l__doc_mat_\int_to_alph:n {#1}_seq
}
\newcommand{\mxm}[1]{
\doc_extract_square_bracket:nN {#1} \l_doc_tmpd_seq
\seq_get_left:NN \l_doc_tmpd_seq \l_doc_tmpa_tl
\exp_args:NV \doc_extract_square_bracket:nN \l_doc_tmpa_tl \l_doc_tmpe_seq
\int_set:Nn \l_doc_tmpb_int {\seq_count:N \l_doc_tmpe_seq}
\seq_show:N \l_doc_tmpd_seq
\int_step_inline:nn {\l_doc_tmpb_int} {
\seq_clear:c {\doc_temp_seq_name:n {##1}}
}
\seq_map_variable:NNn \l_doc_tmpd_seq \l_doc_tmpa_tl {
\exp_args:NV \doc_extract_square_bracket:nN \l_doc_tmpa_tl \l_doc_tmpe_seq
\int_set:Nn \l_doc_tmpc_int {1}
\seq_map_variable:NNn \l_doc_tmpe_seq \l_doc_tmpb_tl {
\tl_clear:N \l_doc_tmpc_tl
\tl_put_right:Nn \l_doc_tmpc_tl {[}
\tl_put_right:NV \l_doc_tmpc_tl \l_doc_tmpb_tl
\tl_put_right:Nn \l_doc_tmpc_tl {]}
\seq_put_right:cV {\doc_temp_seq_name:n {\l_doc_tmpc_int}} \l_doc_tmpc_tl
\int_incr:N \l_doc_tmpc_int
}
}
\int_step_inline:nn {\l_doc_tmpb_int} {
\tl_set:Nx \l_doc_tmpa_tl {\exp_not:N\x{\seq_use:cn {\doc_temp_seq_name:n {##1}} {}}}
\tl_use:N \l_doc_tmpa_tl
}
}
\ExplSyntaxOff
\begin{document}
$$\x{[1,2,3][4,5,6][7,8,9]}$$
$$\x{[1,2,3,4,5,6][a,b,c,d,e,f][6,5,4,3,2,1]}$$
$$\x{[1,2][3,4][5,6][7,8][9,10][11,12]}$$
$$
\mxm{
[ [3,2]*[-3, 0]*[ 1,-2] ]
[ [1,1]*[ 0,-2]*[-1, 3] ]
}
$$
$$
\mxm{
[ [3,2]+[-3, 0]+[ 1,-2] ]
[ [1,1]+[ 0,-2]+[-1, 3] ]
}
$$
$$
\mxm{
[ [3,2][-3, \alpha][ 1,-2][5,6] ]
[ [1,1][ 0,-2][-1, 3][5,6] ]
[ [1,1][ 0,-2][-1, 3][5,6] ]
[ [1,1][ 0,-2][-1, 3][5,6] ]
[ [1,1][ 0,-2][-1, 3][5,6] ]
[ [1,1][ 0,-2][\frac{3}{2}, 3][5,6] ]
}
$$
\end{document}