使用生成的可选参数调用命令

使用生成的可选参数调用命令

我正在开发一个宏,将来它可以为我节省很多时间。目前,我想要的一个命令已经运行,但第二部分运行起来却遇到了麻烦。第一个命令定义如下:

\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}

相关内容