\newcommand 带有许多参数

\newcommand 带有许多参数

我正在尝试构建一个显示某种清单的命令。理想情况下,我只想将一组布尔值传递给该命令。

一个简单的 MWE 如下所示:

\documentclass{article}
\usepackage{tabularx}

\newcommand{\mychecklist}[5]{
    \begin{table}
        \begin{tabularx}{\textwidth}{|l|l|}
            param 1 & #1 \\
            param 2 & #2 \\
            param 3 & #3 \\
            param 4 & #4 \\
            param 5 & #5
        \end{tabularx}
    \end{table}
}

\begin{document}
\mychecklist{x}{}{x}{}{x}
\end{document}

但是,我需要传递超过 9 个参数。我该如何有效地做到这一点?有没有一种解决方案可以让我将一组索引(例如[1,3,5])传递给命令并产生所需的结果,即在相应位置带有复选标记的表格?

答案1

由于 30,000 个字符的限制,我不得不将此答案分成四个部分。

这是我的回答的第一部分。

第1部分包括如何将事物划分为不同的子程序然后组合成所需机制的解释。

第2部分\usepackage由几个可以通过/加载的包文件/.sty 文件组成,\RequirePackage这些文件/文件附带一些所需的子程序。

第 3 部分\usepackage还包含几个可以通过/加载的包文件/.sty 文件\RequirePackage,这些文件带有一些所需的子程序。

第 4 部分提供一个 LaTeX 文档,该文档通过\RequirePackage/\usepackage加载包含所需子程序的包第2部分第 3 部分. 在该文档的头部,甚至在序言之前,这些子程序用于组合所需的通用和非通用用户级宏。

为了进行测试,请将提供的包文件/.sty 文件保存在第2部分第 3 部分以及text.tex来自第 4 部分在同一目录中并test.tex使用 LaTeX 引擎进行编译。


你可以把这个问题作为从头开始实现事情的一个很好的练习。

通过本练习你可以展示有用的 (La)TeX 编程技术:

  • \romannumeral0-expansion 作为触发扩展的手段,直到获得期望的结果/期望的一组 token。
    (我\romannumeral0我对这个问题的回答是“如何知道在附加到 csname 宏时 expandafter 的数量?”
  • 尾递归仅通过对逗号分隔参数列表/非分隔参数列表的单个元素进行(宏)扩展来进行迭代。
  • 尾递归用于在尾递归宏的特定参数内累积所需的结果/所需的标记集。
  • 在触发所需的扩展后,嵌套调用宏\UD@PassThirdBeforeFirstToSecond/交换宏参数,作为一种系统方法,用于在让(La)TeX 再次调用/扩展有问题的尾递归宏之前,将尾递归宏的(已更改的)参数正确地放置在标记流中。

使用所需命令,\mychecklist“索引集”[1,3,5]形成逗号分隔的参数列表。因此,这个问题包括处理逗号分隔的宏参数列表的任务。

从逗号分隔的参数列表(逗号列表)中提取元素(例如第一个元素)是一项有趣的任务:

出现了几个问题。例如,关于如何处理此类元素的前导和尾随空格标记的问题。例如,关于如何处理逗号不应作为两个元素之间的分隔符而应作为此类元素的组成部分的情况的问题。

在包文件中UD_ExtractFirstCommaDelimitedArg_2019_09_03.sty我实现了\UD@ExtractFirstCommaArg提取逗号列表第一个元素的例程,其中所有可能围绕逗号的空格全部的元素被删除,然后一层花括号可能会包围全部的元素也被剥离。

这样,你就可以将整个元素用括号括起来以便隐藏

  • 逗号不得将元素彼此分开,而应属于相关元素本身。
  • 前导空格和尾随空格不应从相关元素中删除,而应属于相关元素。

这种方法比本场景中需要的更通用。不过我认为值得介绍一下,因为它在其他场景中非常有用。

逗号列表可以包含空格。这些将被悄悄删除:[1 , 3 ,5, 7,9 ,]。单个数字/索引可以嵌套在一层花括号中:[1 , {3} ,5, {7},9 ,]。但是,例如,使用[1 , 3 5 , {7},9 ,],序列3 5将被视为逗号列表的一个元素。由于3和之间的空格5,该元素不形成数字序列/不形成有效数字,除非通过错误消息抱怨它,否则 LaTeX 将忽略它。


通用命令的可能工作流程

\mychecklistwithparameternames{⟨list of comma separated integer numbers in range 1..L⟩}%
                              {⟨list of L names of the L parameters⟩}%
                              {⟨name of macro that did call \mychecklistwithparameternames⟩}%
                              {⟨tokens to insert before the tabularx environment⟩}%
                              {⟨tokens to insert behind the tabularx environment⟩}%

可能:

⤷ 该命令扩展为:

\DetectAmountOfParametersAndInitFlagsLoop{⟨list of L names of the L parameters (where elements get removed during the loop)⟩}% 
                                         {⟨to-be-constructed list of L flags (one flag for each of the L parameters)⟩}% initially empty.
                                         {⟨amount of parameters⟩}% initially 0.
                                         {⟨list of comma separated integer numbers in range 1..L⟩}%
                                         {⟨list of L names of the L parameters (where elements do not get removed so that it can be used after the loop)⟩}%
                                         {⟨name of macro that did call \mychecklistwithparameternames⟩}%
                                         {⟨tokens to insert before the tabularx environment⟩}%
                                         {⟨tokens to insert behind the tabularx environment⟩}%

\DetectAmountOfParametersAndInitFlagsLoop是检测并根据非分隔参数列表⟨amount of parameters⟩创建一个,其中每个标志都初始化为一个参数 :⟨list of L flags (one flag for each of the L parameters)⟩{0}

\DetectAmountOfParametersAndInitFlagsLoop通过尾部递归(即通过改变其参数再次调用自身)进行迭代,直到⟨list of L names of the L parameters (where elements get removed during the loop)⟩该列表形成一个空白的非分隔宏参数(在这种情况下,“空白”表示形成参数的标记集为空或仅包含空格标记):在每次迭代中,从该列表中删除第一个元素并向中添加⟨to-be-constructed list of L flags (one flag for each of the L parameters)⟩另一个标志元素{0}并增加⟨amount of parameters⟩

(这意味着\DetectAmountOfParametersAndInitFlagsLoop需要执行以下任务的子程序:

  1. 检查宏参数是否为空。
    在示例中test.tex来自第 4 部分\UD@CheckWhetherBlank这是UD_Paraphernalia_2019_09_03.sty
  2. 将整数加 1。
    在示例中test.tex来自第 4 部分\UD@Increment这是UD_Increment_2019_09_03.sty
  3. 从非分隔参数列表中删除一个元素。
    在示例中test.tex来自第 4 部分这是通过 完成的。)\UD@FirstOfTwo{}⟨list of non-delimited arguments⟩

当递归迭代完成时,即当⟨list of L names of the L parameters (where elements get removed during the loop)⟩是一个空白的非分隔宏参数时,则终止 \DetectAmountOfParametersAndInitFlagsLoop尾递归并调用另一个尾递归宏\SetFlagsNWarningsLoop

\SetFlagsNWarningsLoop{⟨list of comma separated integer numbers in range 1..L⟩}%
                      {⟨list of L flags (one flag for each of the L parameters)⟩}% all now initialized "{0}".
                      {⟨list of warnings⟩}% initially empty.
                      {⟨amount of parameters⟩}%
                      {⟨list of L names of the L parameters⟩}%
                      {⟨name of macro that did call \mychecklistwithparameternames⟩}%
                      {⟨tokens to insert before the tabularx environment⟩}%
                      {⟨tokens to insert behind the tabularx environment⟩}%

\SetFlagsNWarningsLoop通过尾递归迭代来⟨list of comma separated integer numbers in range 1..L⟩改变中的那些标志,⟨List of L flags (one flag for each of the L parameters)⟩{1}数字出现在⟨list of comma separated integer numbers in range 1..L⟩ :

只要⟨list of comma separated integer numbers in range 1..L⟩不为空,\SetFlagsNWarningsLoop在改变\UD@PassThirdBeforeFirstToSecond其参数(并通过嵌套技术实现)后就会再次调用自身,如下所示:

  • 如果第一个元素为⟨list of comma separated integer numbers in range 1..L⟩
    ,则不执行任何操作
    ,否则
    • 如果第一个元素⟨list of comma separated integer numbers in range 1..L⟩可以取正整数 K,且 1 ≤ K ≤ ⟨amount of parameters⟩
      • ⟨list of L flags (one for flag each of the L parameters)⟩,然后用元素替换第 K 个元素{1}
      • ,否则向中添加一个条目⟨list of warnings⟩
  • 移除 的第一个元素⟨list of comma separated integer numbers in range 1..L⟩

当为⟨list of comma separated integer numbers in range 1..L⟩空时,\SetFlagsNWarningsLoop通过调用来终止尾递归\TableRowsLoop

(这意味着\SetFlagsNWarningsLoop需要执行以下任务的子程序:

  1. 检查宏参数是否为空。
    在示例中test.tex来自第 4 部分\UD@CheckWhetherNull这是UD_Paraphernalia_2019_09_03.sty
  2. 检查宏参数是否为空。
    在示例中test.tex来自第 4 部分\UD@CheckWhetherBlank这是来自[ ]的例行公事UD_Paraphernalia_2019_09_03.sty
  3. 提取逗号分隔列表的第一个元素。
    在示例中test.tex来自第 4 部分\UD@ExtractFirstCommaArg这是UD_ExtractFirstCommaDelimitedArg_2019_09_03.sty
  4. 从逗号分隔列表中删除第一个元素。
    在示例中test.tex来自第 4 部分\UD@GobbleToComma这是来自的宏UD_ExtractFirstCommaDelimitedArg_2019_09_03.sty
  5. 检查参数是否为指定范围内的正整数。
    在示例中test.tex来自第 4 部分\UD@CheckWhetherDigitTokensInRangeOnly这是UD_NumCheck_2019_09_03.sty
  6. 将非分隔参数列表中的第 K 个元素替换为其他元素。
    在示例中test.tex来自第 4 部分\UD@ReplaceKthArg这是UD_ReplaceKthUndelimited_2019_09_03.sty
  7. 发出警告消息。
    在示例中test.tex来自第 4 部分\UD@NotANumberInValidRangeError这是UD_NumCheck_2019_09_03.sty。 )

\TableRowsLoop也是尾递归的,需要按如下方式调用:

\TableRowsLoop{⟨list of L flags (one flag for each of the L parameters)⟩}%
              {⟨list of L names of the L parameters⟩}%
              {⟨table-rows constructed so far⟩}% initially empty.
              {⟨list of warnings⟩}%
              {⟨tokens to insert before the tabular xenvironment⟩}%
              {⟨tokens to insert behind the tabularx environment⟩}%

\TableRowsLoop通过尾递归对⟨list of L flags (one flag for each of the L parameters)⟩和进行迭代⟨list of L names of the L parameters⟩并创建表行:

⟨list of L flags (one flag for each of the L parameters)⟩为空时
,则

  • 终止尾部递归循环,
  • “吐出”:
    • ⟨tokens to insert before the tabularx environment⟩
    • 嵌套⟨table-rows constructed so far⟩在表格和表格环境中,
    • ⟨tokens to insert behind the tabularx environment⟩
    • ⟨list of warnings⟩

否则\TableRowsLoop在改变\UD@PassThirdBeforeFirstToSecond其参数(并通过嵌套技术实现)后再次调用自身,如下所示:

  • 如果⟨list of L flags (one flag for each of the L parameters)⟩ 仅包含一个元素(最后一个元素)
    • ,那么:
      如果的第一个元素⟨list of L flags (one flag for each of the L parameters)⟩表示数字 0
      • ,然后将序列添加
        ⟨first element of the ⟨list of L names of the L parameters⟩⟩&
        ⟨table-rows constructed so far⟩
      • ,否则将序列添加
        ⟨first element of the ⟨list of L names of the L parameters⟩&x
        ⟨table-rows constructed so far⟩
    • ,否则:
      如果第一个元素⟨list of L flags (one flag for each of the L parameters)⟩表示数字 0
      • ,然后将序列添加
        ⟨first element of the ⟨list of L names of the L parameters⟩⟩&\\
        ⟨table-rows constructed so far⟩
      • ,否则将序列添加
        ⟨first element of the ⟨list of L names of the L parameters⟩&x\\
        ⟨table-rows constructed so far⟩
  • 移除 的第一个元素⟨list of L flags (one flag for each of the L parameters)⟩
  • 移除 的第一个元素⟨list of L names of the L parameters⟩

(这意味着\TableRowsLoop需要执行以下任务的子程序:

  1. 检查非分隔宏参数是否为空。
    在示例中test.tex来自第 4 部分\UD@CheckWhetherNull这是UD_Paraphernalia_2019_09_03.sty
  2. 提取非分隔参数列表的第一个元素。
    在示例中test.tex来自第 4 部分\UD@ExtractFirstArg这是UD_ExtractFirstUndelimitedArg_2019_09_03.sty
  3. 检查宏参数是否表示数字“0”。
    在示例中test.tex来自第 4 部分例行公事\UD@CheckWhetherDigitTokensInRangeOnlyUD_NumCheck_2019_09_03.sty用于此。
  4. 从非分隔参数列表中删除一个元素。
    在示例中test.tex来自第 4 部分这是通过 完成的。)\UD@FirstOfTwo{}⟨list of non-delimited arguments⟩

包文件中提供的子例程,\UD@NotANumberInValidRangeError除了UD_NumCheck_2019_09_03.sty,由于\romannumeral0-expansion 在两个扩展步骤之后/在 两次“命中”之后提供其结果\expandafter

因此,示例中的代码test.tex来自第 4 部分应用 nested-\UD@PassThirdBeforeFirstToSecond技术来为调用尾递归宏的下一个循环实例提供参数,通常需要与在执行交换之前让\UD@PassThirdBeforeFirstToSecond的第一个参数“命中”两次相结合。 这就是为什么\expandafter
UD_Paraphernalia_2019_09_03.sty我实现了一个辅助宏\UD@PassThirdBeforeTwiceExpandedFirstToSecond

根据通用命令,\mychecklistwithparameternames您可以\mychecklist使用语法定义:

\mychecklist[⟨comma list⟩]%
            {⟨caption of the table⟩}%
            {⟨referencing label of the table⟩}

像这样:

\newcommand\mychecklist[3][⟨comma list with defaults⟩]{%
  \mychecklistwithparameternames{#1}%
                                {{param 1}{param 2}..{param L}}%
                                {mychecklist}%
                                {\caption{#2}\label{#3}}% ← We want the caption before the tabular environment
                                {}%
}%

(在示例中test.tex来自第 4 部分不仅会传递\caption和,\label还会测试#2⟨caption⟩)和#3⟨label⟩)是否为空,如果⟨caption⟩为空而⟨label⟩不是,则会传递警告消息,因为通常放置没有标题/没有分段命令的引用标签没有多大意义。)


由于 30,000 个字符的限制,我不得不将此答案分成四个部分。

这是我的回答的第一部分。

第1部分包括如何将事物划分为不同的子程序然后组合成所需机制的解释。

第2部分\usepackage由几个可以通过/加载的包文件/.sty 文件组成,\RequirePackage这些文件/文件附带一些所需的子程序。

第 3 部分\usepackage还包含几个可以通过/加载的包文件/.sty 文件\RequirePackage,这些文件带有一些所需的子程序。

第 4 部分提供一个 LaTeX 文档,该文档通过\RequirePackage/\usepackage加载包含所需子程序的包第2部分第 3 部分. 在该文档的头部,甚至在序言之前,这些子程序用于组合所需的通用和非通用用户级宏。

为了进行测试,请将提供的包文件/.sty 文件保存在第2部分第 3 部分以及text.tex来自第 4 部分在同一目录中并test.tex使用 LaTeX 引擎进行编译。

答案2

作为乌尔里希·迪茨指出,此主题包含适合我的问题的解决方案。

此解决方案禁止使用参数调用其他宏。我将其包装在另一个命令中,以便可以添加标签和标题。如下所示:

\usepackage{xparse}
\usepackage{tabularx}

% I copied & pasted this part:
\ExplSyntaxOn
\NewDocumentCommand{\newlongcommand}{mm}
{% #1 = command to define, #2 = replacement text
    \cs_new:Npn #1 ##1
    {
        \tl_set:Nn \l__simon_args_tl { ##1 }
        #2
    }
}
\NewDocumentCommand{\Arg}{m}
{
    \tl_item:Nn \l__simon_args_tl { #1 }
}

\tl_new:N \l__simon_parse_args_tl
\ExplSyntaxOff

% the actual command
\newlongcommand{\coretable}{
\begin{tabularx}{\textwidth}{|llX|llX|llX|llX|llX|llX|}
    % my actual stuff
\end{tabularx}
}

% the wrapper
\newcommand{\featuretable}[4]{
\begin{table}[h]
    \caption{Features of #1}
    \label{#2}
    \coretable{#3}
    \vskip0.5em
    #4
\end{table}
}

这叫做

\featuretable{name}{label}{{A1}{A2}{A3}{A4}{B1}{B2}{B3}{C1}{C2}{C3}{C4}{C5}{C6}{D1}{D2}{D3}{E1}{E2}{F1}{F2}}{extra}

答案3

由于 30,000 个字符的限制,我不得不将此答案分成四个部分。

这是我的回答的第二部分。

第1部分包括如何将事物划分为不同的子程序然后组合成所需机制的解释。

第2部分\usepackage由几个可以通过/加载的包文件/.sty 文件组成,\RequirePackage这些文件/文件附带一些所需的子程序。

第 3 部分\usepackage还包含几个可以通过/加载的包文件/.sty 文件\RequirePackage,这些文件带有一些所需的子程序。

第 4 部分提供一个 LaTeX 文档,该文档通过\RequirePackage/\usepackage加载包含所需子程序的包第2部分第 3 部分. 在该文档的头部,甚至在序言之前,这些子程序用于组合所需的通用和非通用用户级宏。

为了进行测试,请保存提供的包文件/.sty 文件第2部分第 3 部分以及text.tex来自第 4 部分在同一目录中并test.tex使用 LaTeX 引擎进行编译。


包裹UD_Paraphernalia_2019_09_03.sty

%%//////////////////////////////////////////////////////////////////////////////
%% AUTHOR
%%
%% Ulrich W. Diez ([email protected])
%%
%% LICENCE AND COPYRIGHT
%%
%% Copyright (C) 2019 by Ulrich W. Diez ([email protected])
%%..............................................................................
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or 
%% (at your option) any later version. 
%% (The latest version of this license is in:
%%    http://www.latex-project.org/lppl.txt
%%  and version 1.3 or later is part of all distributions of 
%%  LaTeX version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included documentation nor for 
%% any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%//////////////////////////////////////////////////////////////////////////////
\NeedsTeXFormat{LaTeX2e}[1994/06/01]%
\ProvidesPackage{UD_Paraphernalia_2019_09_03}%
  [2019/09/03 v 1.0 Nice helper-macros often used by Ulrich Diez. (Ulrich Diez)]%
%%//////////////////////////////////////////////////////////////////////////////
%% PARAPHERNALIA
%% 
%%    \UD@FirstOfTwo, \UD@SecondOfTwo, \UD@Exchange, 
%%    \UD@PassThirdBeforeFirstToSecond, 
%%    \UD@PassThirdBeforeTwiceExpandedFirstToSecond, \UD@CheckWhetherNull, 
%%    \UD@CheckWhetherBrace, \UD@CheckWhetherBlank
%%    
%%==============================================================================
\newcommand\UD@FirstOfTwo[2]{#1}%
\newcommand\UD@SecondOfTwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}% !! \UD@Exchange will return the arguments with
                                % one level of surrounding braces removed if
                                % such braces that surround an argument entirely
                                % are present.
\newcommand\UD@PassThirdBeforeFirstToSecond[3]{#2{#3}{#1}}%
%%------------------------------------------------------------------------------
%% \UD@PassThirdBeforeTwiceExpandedFirstToSecond{<argument 1>}%
%%                                              {<argument 2>}%
%%                                              {<argument 3>}%
%% ->
%% <argument 2>{<argument 3>}{<argument 1 (hit by `\expandafter` twice)>}
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after two
%%   expansion-steps/after having \UD@PassThirdBeforeTwiceExpandedFirstToSecond 
%%   "hit" via two \expandafter(-chains).  )
%%------------------------------------------------------------------------------
\newcommand\UD@PassThirdBeforeTwiceExpandedFirstToSecond[2]{%
  \romannumeral0%
  \expandafter\expandafter\expandafter\UD@PassThirdBeforeFirstToSecond
  \expandafter\expandafter\expandafter{#1}{ #2}%
}%
%%------------------------------------------------------------------------------
%% 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>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@CheckWhetherNull "hit" via
%%   two \expandafter(-chains).  )
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@SecondOfTwo\string{\expandafter
  \UD@SecondOfTwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@SecondOfTwo\string}\expandafter\UD@FirstOfTwo\expandafter{\expandafter
  \UD@SecondOfTwo\string}\UD@FirstOfTwo\expandafter{} %
  \UD@SecondOfTwo}{\UD@FirstOfTwo\expandafter{} \UD@FirstOfTwo}%
}%
%%------------------------------------------------------------------------------
%% Check whether argument is blank (empty or only spaces):
%%..............................................................................
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" non-delimited arguments: --
%%
%% \UD@CheckWhetherBlank{<argument which is to be checked>}%
%%                      {<tokens to be delivered in case that
%%                        argument which is to be checked is blank>}%
%%                      {<tokens to be delivered in case that argument
%%                        which is to be checked is not blank}%
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@CheckWhetherBlank "hit" via
%%   two \expandafter(-chains).  )
\newcommand\UD@CheckWhetherBlank[1]{%
  \romannumeral\expandafter\expandafter\expandafter\UD@SecondOfTwo
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@FirstOfTwo#1{}.}%
}%
%%------------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%..............................................................................
%% \UD@CheckWhetherBrace{<argument which is to be checked>}%
%%                      {<tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@CheckWhetherBrace "hit" via
%%   two \expandafter(-chains).  )
\newcommand\UD@CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\UD@SecondOfTwo\expandafter{\expandafter{%
  \string#1.}\expandafter\UD@FirstOfTwo\expandafter{\expandafter
  \UD@SecondOfTwo\string}\UD@FirstOfTwo\expandafter{} %
  \UD@FirstOfTwo}{\UD@FirstOfTwo\expandafter{} \UD@SecondOfTwo}%
}%
\endinput
%%//////////////////////////////////////////////////////////////////////////////

包裹UD_ExtractFirstUndelimitedArg_2019_09_03.sty

%%//////////////////////////////////////////////////////////////////////////////
%% AUTHOR
%%
%% Ulrich W. Diez ([email protected])
%%
%% LICENCE AND COPYRIGHT
%%
%% Copyright (C) 2019 by Ulrich W. Diez ([email protected])
%%..............................................................................
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or 
%% (at your option) any later version. 
%% (The latest version of this license is in:
%%    http://www.latex-project.org/lppl.txt
%%  and version 1.3 or later is part of all distributions of 
%%  LaTeX version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included documentation nor for 
%% any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%//////////////////////////////////////////////////////////////////////////////
\NeedsTeXFormat{LaTeX2e}[1994/06/01]%
\ProvidesPackage{UD_ExtractFirstUndelimitedArg_2019_09_03}%
  [2019/09/03 v 1.0 Extract first item of non-delimited-argument-list. (Ulrich Diez)]%
\RequirePackage{UD_Paraphernalia_2019_09_03}[2019/09/03]%
%%//////////////////////////////////////////////////////////////////////////////
%% EXPANDABLE EXTRACTION OF FIRST ITEM OF NON-DELIMITED-ARGUMENT-LIST
%% 
%%------------------------------------------------------------------------------
%% Extract first inner non-delimited argument:
%%..............................................................................
%%  \UD@ExtractFirstArg{ABCDE} yields  A
%%  \UD@ExtractFirstArg{{AB}CDE} yields  AB
%%     LaTeX does not gather spaces not nested in braces as (components of) 
%%     non-delimited arguments. Thus:
%%  \UD@ExtractFirstArg{ ABCDE} yields  A
%%  \UD@ExtractFirstArg{ {AB}CDE} yields  AB
%%  !!! The argument wherefrom the first inner non-delimited argument shall !!!
%%  !!! be extracted must itself not be blank.                              !!!
%%  !!! This means:                                                         !!!
%%  !!!    \UD@ExtractFirstArg{} and/or \UD@ExtractFirstArg{ } must not     !!!
%%  !!!    be performed. You can apply \UD@CheckWhetherBlank for checking   !!!
%%  !!!    whether the argument is blank.                                   !!!
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@ExtractFirstArg "hit" via
%%   two \expandafter(-chains).  )
%%------------------------------------------------------------------------------
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
  \long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArg[1]{%
  \romannumeral0%
  \UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@FirstOfTwo{}#1}%
  {\UD@Exchange#1{ }}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
\endinput
%%//////////////////////////////////////////////////////////////////////////////

包裹UD_ReplaceKthUndelimited_2019_09_03.sty

%%//////////////////////////////////////////////////////////////////////////////
%% AUTHOR
%%
%% Ulrich W. Diez ([email protected])
%%
%% LICENCE AND COPYRIGHT
%%
%% Copyright (C) 2019 by Ulrich W. Diez ([email protected])
%%..............................................................................
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or 
%% (at your option) any later version. 
%% (The latest version of this license is in:
%%    http://www.latex-project.org/lppl.txt
%%  and version 1.3 or later is part of all distributions of 
%%  LaTeX version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included documentation nor for 
%% any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
%%//////////////////////////////////////////////////////////////////////////////
\NeedsTeXFormat{LaTeX2e}[1994/06/01]%
\ProvidesPackage{UD_ReplaceKthUndelimited_2019_09_03}%
  [2019/09/03 v 1.0 Replace K-th element of non-delimited-argument-list. (Ulrich Diez)]%
\RequirePackage{UD_Paraphernalia_2019_09_03}[2019/09/03]%
\RequirePackage{UD_ExtractFirstUndelimitedArg_2019_09_03}[2019/09/03]%
%%//////////////////////////////////////////////////////////////////////////////
%% EXPANDABLE REPLACEMENT OF K-TH ELEMENT OF LIST OF NON-DELIMITED
%% MACRO ARGUMENTS
%% 
%%==============================================================================
%% Replace K-th element of list of non-delimited macro arguments:
%%
%%   \UD@ReplaceKthArg{<integer K>}%
%%                    {<replacement>}%
%%                    {<list of non-delimited macro arguments>} 
%% 
%% In case a K-th argument cannot be determined in the
%% <list of non-delimited macro arguments> : 
%%   Does deliver: {<list of non-delimited macro arguments>}
%%
%% In case a K-th argument can be determined in the
%% <list of non-delimited macro arguments> : 
%%   Does deliver: {<list of non-delimited macro arguments>} 
%%                 with the list's K-th element replaced by {<replacement>}
%%
%% Each element of the <list of non-delimited macro arguments> will be nested 
%% in braces afterwards.
%%
%% The <list of non-delimited macro arguments> may be empty.
%% In this case an empty list will be returned.
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@ReplaceKthArg "hit" via
%%   two \expandafter(-chains).  )
%%..............................................................................
%% Examples:
%%
%%   \UD@ReplaceKthArg{0}{c}{{A}{B}{C}{D}{E}} yields: {{A}{B}{C}{D}{E}}
%%
%%   \UD@ReplaceKthArg{3}{c}{{A}{B}{C}{D}{E}} yields: {{A}{B}{c}{D}{E}}
%%
%%   \UD@ReplaceKthArg{1}{aa}{{A}{B}{C}{D}{E}} yields: {{aa}{B}{C}{D}{E}}
%%
%%   \UD@ReplaceKthArg{4}{four}{{A}{B}{C}{D}{E}} yields: {{A}{B}{C}{four}{E}}
%%
%%   \UD@ReplaceKthArg{6}{six}{{A}{B}{C}{D}{E}} yields: {{A}{B}{C}{D}{E}}
%% 
%%   \UD@ReplaceKthArg{0}{c}{ABCDE} yields: {{A}{B}{C}{D}{E}}
%%
%%   \UD@ReplaceKthArg{3}{c}{ABCDE} yields: {{A}{B}{c}{D}{E}}
%%
%%   \UD@ReplaceKthArg{1}{aa}{ABCDE} yields: {{aa}{B}{C}{D}{E}}
%%
%%   \UD@ReplaceKthArg{4}{four}{ABCDE} yields: {{A}{B}{C}{four}{E}}
%%
%%   \UD@ReplaceKthArg{6}{six}{ABCDE} yields: {{A}{B}{C}{D}{E}}
%% 
%%   \UD@ReplaceKthArg{6}{six}{} yields: {}
%%
%%==============================================================================
\newcommand\UD@ReplaceKthArg[1]{%
  % #1: <integer K>
  \romannumeral0%
  \expandafter\UD@ReplaceKthArgCheck
  \expandafter{\romannumeral\number\number#1 000}%
}%
\newcommand\UD@ReplaceKthArgCheck[3]{%
  % #1: <amount of K letters m>
  % #2: <replacement>
  % #3: <list of non-delimited macro arguments>
  \UD@CheckWhetherNull{#1}{%
    \UD@ReplaceKthArgLoop{}{}{#3}{}{m}%
  }{%
    \expandafter\UD@ReplaceKthArgLoop
    \expandafter{\expandafter}\expandafter{\UD@FirstOfTwo{}#1}{#3}{#2}{}%
  }%
}%
\newcommand\UD@ReplaceKthArgLoop[5]{%
  % #1: <new list of non-delimited macro arguments>
  % #2: <amount of K letters m>
  % #3: <list of non-delimited macro arguments>
  % #4: <Replacement>
  % #5: <indicator whether replacement already took place. 
  %     "m" in this case. Empty otherwise.>
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@FirstOfTwo#3{}.}{ {#1}}{%
    \UD@CheckWhetherNull{#5#2}{%
      \expandafter\UD@Exchange\expandafter{\expandafter{\UD@FirstOfTwo{}#3}}{%
        \UD@ReplaceKthArgLoop{#1{#4}}{}%
      }{}{m}%
    }{%
      \expandafter\UD@Exchange\expandafter{\expandafter{\UD@FirstOfTwo{}#3}}{%
        \expandafter\UD@Exchange\expandafter{%
        \expandafter{\UD@FirstOfTwo{}#5#2}}{%
          \expandafter\UD@ReplaceKthArgLoop\expandafter{%
            \romannumeral0%
            \UD@FirstOfTwo{\expandafter\expandafter\expandafter}{} %
            \expandafter\UD@Exchange\expandafter{\expandafter{%
              \romannumeral0\UD@ExtractFirstArgLoop{#3\UD@SelDOm}%
            }}{#1}%
          }%
        }%
      }{#4}{#5}%
    }%
  }%
}%
\endinput
%%//////////////////////////////////////////////////////////////////////////////

包裹UD_TrimSpaces_2019_09_03.sty

%%//////////////////////////////////////////////////////////////////////////////
%% AUTHOR
%%
%% Ulrich W. Diez ([email protected])
%%
%% LICENCE AND COPYRIGHT
%%
%% Copyright (C) 2019 by Ulrich W. Diez ([email protected])
%%..............................................................................
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or 
%% (at your option) any later version. 
%% (The latest version of this license is in:
%%    http://www.latex-project.org/lppl.txt
%%  and version 1.3 or later is part of all distributions of 
%%  LaTeX version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included documentation nor for 
%% any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
%%//////////////////////////////////////////////////////////////////////////////
\NeedsTeXFormat{LaTeX2e}[1994/06/01]%
\ProvidesPackage{UD_TrimSpaces_2019_09_03}%
  [2019/09/03 v 1.0 Trim spaces that surround token sequences. (Ulrich Diez)]%
\RequirePackage{UD_Paraphernalia_2019_09_03}[2019/09/03]%
%%//////////////////////////////////////////////////////////////////////////////
%% EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES
%%
%%   The obscure case of removing several leading/trailing spaces was taken 
%%   into consideration.
%%
%%   Removal of spaces was implemented in a way where no brace-stripping from
%%   the arguments takes place. 
%%   Explicit-catcode-1/2-character-token-pairs remain untouched.
%%
%%   Spaces interspersing the argument or hidden within braces will be left in
%%   place.
%%
%%   The arguments themselves do not get expanded.
%%
%%   (For some obscure reason I don't remember any more I needed this in the
%%    past.)
%%
%%==============================================================================
%% Check whether brace-balanced argument starts with a space-token
%%..............................................................................
%% \UD@CheckWhetherLeadingSpace{<argument which is to be checked>}%
%%                             {<tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@CheckWhetherLeadingSpace "hit" via
%%   two \expandafter(-chains).  )
%%==============================================================================
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\UD@Exchange{ }\expandafter\UD@SecondOfTwo}%
  {\expandafter\UD@SecondOfTwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\@ifdefinable\UD@CheckWhetherLeadingSpaceB{%
  \long\def\UD@CheckWhetherLeadingSpaceB#1 {%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@SecondOfTwo#1{}}%
    {\UD@Exchange{\UD@FirstOfTwo}}{\UD@Exchange{\UD@SecondOfTwo}}%
    {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
     \expandafter\expandafter\expandafter}\expandafter\expandafter
     \expandafter}\expandafter\UD@SecondOfTwo\expandafter{\string}%
  }%
}%
%%==============================================================================
%% \UD@TrimAllLeadSpace{<argument>} 
%%..............................................................................
%%   Expandably removes all leading spaces from  <argument> in case at least
%%   one leading space is present. 
%%   Then
%%     <argument without leading spaces>
%%   is delivered.
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@TrimAllLeadSpace "hit" via
%%   two \expandafter(-chains).  )
%%==============================================================================
\newcommand\UD@TrimAllLeadSpace[1]{%
  \romannumeral0\UD@TrimAllLeadSpaceLoop{#1}%
}%
\newcommand\UD@TrimAllLeadSpaceLoop[1]{%
  \UD@CheckWhetherLeadingSpace{#1}%
                            {%
                              \expandafter\UD@TrimAllLeadSpaceLoop
                              \expandafter{\UD@RemoveSpace#1}%
                            }%
                            { #1}%
}%
\@ifdefinable\UD@RemoveSpace{\UD@FirstOfTwo{\def\UD@RemoveSpace}{} {}}%
%%==============================================================================
%% \UD@TrimAllTrailSpace{<argument>} 
%%..............................................................................
%%   Expandably removes all trailing spaces from  <argument> in case at least
%%   one trailing space is present. 
%%   Then
%%     <argument without trailing spaces>
%%   is delivered.
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@TrimAllTrailSpace "hit" via
%%   two \expandafter(-chains).  )
%%==============================================================================
\newcommand\UD@TrimAllTrailSpace[1]{%
   \romannumeral0\UD@TrimTrailSpaceLoop{#1}%
}%
%%------------------------------------------------------------------------------
%% \UD@TrimTrailSpaceLoop{<list of space-delimited arguments>}
%%..............................................................................
%%   Both extracts the first space-delimited argument from the <list of space-
%%   delimited arguments> as {<current argument with one trailing space 
%%   removed>} and removes it from the <list of space-delimited arguments> for
%%   obtaining the <remaining list of space delimited arguments> and passes 
%%   these two things and an empty list of <arguments preceding the current
%%   argument gathered so far>  at the end of the iteration to 
%%   \UD@CheckWhetherLastSpaceDelimitedItem.
%%
%%   \UD@CheckWhetherLastSpaceDelimitedItem in turn does choose the next
%%   action.
%%------------------------------------------------------------------------------
\newcommand\UD@TrimTrailSpaceLoop[1]{%
  %#1 argument
  \UD@ObtainFirstSpaceDelimitedTokenSetLoop{.#1 \UD@SeLDom}{%
    \expandafter\UD@CheckWhetherLastSpaceDelimitedItem
    \expandafter{\UD@RemoveTokensTillNextSpace.#1 }%
  }{}%
}%
%%------------------------------------------------------------------------------
%% Macros for \UD@ObtainFirstSpaceDelimitedTokenSetLoop.
%%------------------------------------------------------------------------------
\@ifdefinable\UD@RemoveTokensTillNextSpace{%
  \long\def\UD@RemoveTokensTillNextSpace#1 {}%
}%
\@ifdefinable\UD@BraceStripRemoveNextSpace{%
  \long\def\UD@BraceStripRemoveNextSpace#1 {#1}%
}%
\@ifdefinable\UD@GetFirstSpaceDelimitedTokenSet{%
  \long\def\UD@GetFirstSpaceDelimitedTokenSet#1 #2\UD@SeLDom{#1 }%
}%
\@ifdefinable\UD@GobbleDot{%
  \def\UD@GobbleDot.{}%
}%
%%------------------------------------------------------------------------------
%% \UD@ObtainFirstSpaceDelimitedTokenSetLoop%
%%     {<list of space delimited arguments>}%
%%     {<action>}%
%%
%% -> <action>{<first element of list of space delimited arguments>}%
%%...............................................................................
%% \UD@ObtainFirstSpaceDelimitedTokenSetLoop does--without unwanted brace-re-
%% moval--append the first space delimited argument from a
%% <list of space delimited arguments> as brace-delimited argument behind
%% a set of tokens given as <action>.
%%------------------------------------------------------------------------------
\newcommand\UD@ObtainFirstSpaceDelimitedTokenSetLoop[1]{%
  \expandafter\UD@CheckWhetherNull
  \expandafter{\UD@RemoveTokensTillNextSpace#1}{%
    \expandafter\expandafter\expandafter\UD@Exchange
    \expandafter\expandafter\expandafter{%
    \expandafter\expandafter\expandafter{%
    \expandafter\UD@GobbleDot\UD@BraceStripRemoveNextSpace#1}}%
  }{%
    \expandafter\UD@ObtainFirstSpaceDelimitedTokenSetLoop
    \expandafter{\UD@GetFirstSpaceDelimitedTokenSet#1}%
  }%
}%
%%------------------------------------------------------------------------------
%% \UD@CheckWhetherLastSpaceDelimitedItem
%%    {<remaining list of space delimited arguments>}%
%%    {<current argument with one trailing space removed>}%
%%    {<arguments preceding the current argument gathered
%%      so far>}%
%%..............................................................................
%% Case 1: <remaining list of space delimited arguments> is
%%         empty.
%%         We are done: Thus:
%%         <space> for terminating \romannumeral-expansion, and
%%         <arguments preceding the current argument gathered so
%%         far><current argument with one trailing space removed>
%% Case 2: <remaining list of space delimited arguments> consists of a single 
%%         space.
%%         A trailing space was removed. There may be more. Thus:
%%         \UD@TrimTrailSpaceLoop{%
%%           <arguments preceding the current argument gathered so
%%           far><current argument with one trailing space removed>%
%%         }%
%% Neither case 1 nor case 2: 
%%         The <current argument with one trailing space  removed> is not the
%%         last argument of the list, thus:
%%         For the next iteration 
%%         - attach it and a trailing space to the <arguments preceding the
%%           current argument gathered so far>,
%%         - get the first space delimited argument of the <remaining list of 
%%           space delimited arguments> as  <current argument with one trailing
%%           space removed>
%%         - remove that first space delimited argument from the <remaining list 
%%           of space delimited arguments>
%%------------------------------------------------------------------------------
\newcommand\UD@CheckWhetherLastSpaceDelimitedItem[3]{%
  \UD@CheckWhetherNull{#1}{ #3#2}{%
    \UD@CheckWhetherLeadingSpace{#1}{%
      \expandafter\UD@CheckWhetherNull
      \expandafter{\UD@RemoveSpace#1}{\UD@FirstOfTwo}{\UD@SecondOfTwo}%
    }{\UD@SecondOfTwo}%
    {\UD@TrimTrailSpaceLoop{#3#2}}%
    {%
      \UD@ObtainFirstSpaceDelimitedTokenSetLoop{.#1\UD@SeLDom}{%
        \expandafter\UD@CheckWhetherLastSpaceDelimitedItem
        \expandafter{\UD@RemoveTokensTillNextSpace.#1}%
      }{#3#2 }%
    }%
  }%
}%
%%==============================================================================
%% \UD@TrimAllSurroundSpace{<argument>} 
%%..............................................................................
%%   expandably removes all leading and trailing spaces from  <argument> in
%%   case at least one leading space is present. 
%%   Then
%%     <argument without leading and trailing spaces>
%%   is delivered.
%%
%% ( Due to \romannumeral0-expansion, the result will be delivered after
%%   two expansion-steps/after having \UD@TrimAllSurroundSpace "hit" via
%%   two \expandafter(-chains).  )
%%==============================================================================
\newcommand\UD@TrimAllSurroundSpace[1]{%
  \romannumeral0\expandafter\UD@TrimTrailSpaceLoop
                \expandafter{\romannumeral0\UD@TrimAllLeadSpaceLoop{#1}}%
}%
\endinput
%%//////////////////////////////////////////////////////////////////////////////

答案4

由于 30,000 个字符的限制,我不得不将此答案分成四个部分。

这是我的答案的第四部分。

第1部分包括如何将事物划分为不同的子程序然后组合成所需机制的解释。

第2部分\usepackage由几个可以通过/加载的包文件/.sty 文件组成,\RequirePackage这些文件/文件附带一些所需的子程序。

第 3 部分\usepackage还包含几个可以通过/加载的包文件/.sty 文件\RequirePackage,这些文件带有一些所需的子程序。

第 4 部分提供一个 LaTeX 文档,该文档通过\RequirePackage/\usepackage加载包含所需子程序的包第2部分第 3 部分. 在该文档的头部,甚至在序言之前,这些子程序用于组合所需的通用和非通用用户级宏。

为了进行测试,请保存提供的包文件/.sty 文件第2部分第 3 部分以及text.tex来自第 4 部分在同一目录中并test.tex使用 LaTeX 引擎进行编译。


带有用户级宏和测试文档的文本文件test.tex

%%//////////////////////////////////////////////////////////////////////////////
%% AUTHOR
%%
%% Ulrich W. Diez ([email protected])
%%
%% LICENCE AND COPYRIGHT
%%
%% Copyright (C) 2019 by Ulrich W. Diez ([email protected])
%%..............................................................................
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or 
%% (at your option) any later version. 
%% (The latest version of this license is in:
%%    http://www.latex-project.org/lppl.txt
%%  and version 1.3 or later is part of all distributions of 
%%  LaTeX version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included documentation nor for 
%% any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
%%//////////////////////////////////////////////////////////////////////////////
\RequirePackage{UD_Paraphernalia_2019_09_03}[2019/09/03]%
\RequirePackage{UD_ExtractFirstUndelimitedArg_2019_09_03}[2019/09/03]%
\RequirePackage{UD_ReplaceKthUndelimited_2019_09_03}[2019/09/03]%
\RequirePackage{UD_TrimSpaces_2019_09_03}[2019/09/03]%
\RequirePackage{UD_ExtractFirstCommaDelimitedArg_2019_09_03}[2019/09/03]%
\RequirePackage{UD_Increment_2019_09_03}[2019/09/03]%
\RequirePackage{UD_NumCheck_2019_09_03}[2019/09/03]%
%%//////////////////////////////////////////////////////////////////////////////
%% GENERIC USER-LEVEL-MACROS
%%
\makeatletter
%%==============================================================================
%% Automatic creation of a checklist-table for parameters from 
%% - a comma-list with index-numbers denoting parameters and
%% - a list of parameter-names.
%% - Tokens to insert before the tokens that form the tabularx-environment with
%%   the checklist table can be provided.
%% - Tokens to insert behind the tokens that form the tabularx-environment with
%%   the checklist table can be provided.
%%
%% Index number 1 occuring in the comma-list means that the parameter
%% whose name is the first element in the list of parameter-names is 
%% checked.
%% Index number K means that the parameter whose name is the K-th
%% element in the list of parameter-names is checked.
%%
%% That table comes as a table-environment holding a tabularx-environment.
%%
%% In case an error-message needs to be raised, the <name of macro that did 
%% call \mychecklistwithparameternames> is included into that message.
%%..............................................................................
%% \mychecklistwithparameternames{<list of comma separated 
%%                                 index-numbers>}%
%%                               {<list of undelimited arguments for L names 
%%                                 of the L parameters>}%
%%                               {<name of macro that did call 
%%                                 \mychecklistwithparameternames>}%
%%                               {<tokens to insert before the 
%%                                 tabularx environment>}%
%%                               {<tokens to insert behind the
%%                                 tabularx environment>}%
%%
%% ( Due to \romannumeral0-expansion, the tokens that form the table and
%%   probably some error-messages  will be delivered after
%%   two expansion-steps/after having \mychecklistwithparameternames 
%%   "hit" via two \expandafter(-chains).  )
%%==============================================================================
\newcommand\mychecklistwithparameternames[5]{%
  % #1 = <list of comma separated arguments>
  % #2 = <list of L names of the L parameters>
  % #3 = <name of macro that did call \mychecklistwithparameternames>
  % #4 = <tokens to insert before the tabularx environment>
  % #4 = <tokens to insert behind the tabularx environment>
  \romannumeral0%
  \DetectAmountOfParametersAndInitFlagsLoop{#2}{}{0}{#1}{#2}{#3}{#4}{#5}%
}%
\newcommand\DetectAmountOfParametersAndInitFlagsLoop[8]{%
  % #1 = <list of L names of the L parameters (where elements get removed 
  %       during the loop)>
  % #2 = <to-be-constructed list of L flags (one flag for each of the 
  %       L parameters)>
  % #3 = <amount of parameters>
  % #4 = <list of comma separated arguments>
  % #5 = <list of L names of the L parameters (where elements do not get
  %       removed so that it can be used after the loop)>
  % #6 = <name of macro that did call \mychecklistwithparameternames>
  % #7 = <tokens to insert before the tabularx environment>
  % #8 = <tokens to insert behind the tabularx environment>
  \UD@CheckWhetherBlank{#1}{%
    \SetFlagsNWarningsLoop{#4}{#2}{}{#3}{#5}{#6}{#7}{#8}%
  }{%
     \UD@PassThirdBeforeTwiceExpandedFirstToSecond{\UD@Increment{#3}}{%
       \UD@PassThirdBeforeFirstToSecond{#2{0}}{%
          \UD@SecondOfTwo{}%
       }%
     }%
     {%
       \expandafter\DetectAmountOfParametersAndInitFlagsLoop
       \expandafter{\UD@FirstOfTwo{}#1}%
     }%
     {#4}{#5}{#6}{#7}{#8}%
  }%
}%
\newcommand\SetFlagsNWarningsLoop[8]{%
  % #1 = <list of comma separated arguments>
  % #2 = <list of L flags (one flag for each of the L parameters)>
  % #3 = <list of warnings>
  % #4 = <amount of parameters>
  % #5 = <list of L names of the L parameters>
  % #6 = <name of macro that did call \mychecklistwithparameternames>
  % #7 = <tokens to insert before the tabularx environment>
  % #8 = <tokens to insert behind the tabularx environment>
  \UD@CheckWhetherBlank{#1}{%
    \TableRowsLoop{#2}{#5}{}{#3}{#7}{#8}%
  }{%
    \UD@PassThirdBeforeTwiceExpandedFirstToSecond{%
      \UD@ExtractFirstCommaArg{#1}%
    }{%
      \UD@SecondOfTwo{}%
    }{%
      \UD@CheckWhetherNull
    }{%
      \UD@Exchange{{#2}{#3}}%
    }{%
      \UD@PassThirdBeforeTwiceExpandedFirstToSecond{%
        \UD@ExtractFirstCommaArg{#1}%
      }{%
        \UD@SecondOfTwo{}%
      }{%
        \UD@CheckWhetherDigitTokensInRangeOnly
      }%
      {1}{#4}{%
        \UD@PassThirdBeforeFirstToSecond{#3}{%
          \expandafter\expandafter\expandafter
          \UD@PassThirdBeforeFirstToSecond
          \UD@ReplaceKthArg{\UD@ExtractFirstCommaArg{#1}}{1}{#2}{%
            \UD@SecondOfTwo{}%
          }%
        }%
      }{%
        \UD@PassThirdBeforeTwiceExpandedFirstToSecond{%
          \UD@PassThirdBeforeTwiceExpandedFirstToSecond{%
            \UD@ExtractFirstCommaArg{#1}%
          }{%
            #3\UD@NotANumberInValidRangeError
          }{#6}{optional}{1}{#4}%
        }{%
          \UD@PassThirdBeforeFirstToSecond{#2}{%
            \UD@SecondOfTwo{}%
          }%
        }%
      }%
    }%
    {%
      \expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToComma#1,}{%
        \SetFlagsNWarningsLoop{}%
      }{%
        \expandafter\SetFlagsNWarningsLoop\expandafter{\UD@GobbleToComma#1}%
      }%
    }%
    {#4}{#5}{#6}{#7}{#8}%
  }%
}%
\newcommand\TableRowsLoop[6]{%
  % #1 = <list of L flags (one flag for each of the L parameters)>
  % #2 = <list of L names of the L parameters>
  % #3 = <table-rows constructed so far>
  % #4 = <list of warnings>
  % #5 = <tokens to insert before the tabularx environment>
  % #6 = <tokens to insert behind the tabularx environment>
  \UD@CheckWhetherNull{#1}{%
    \UD@CheckWhetherNull{#3}{ }{ %<-This space must be!
      \begin{table}%
      #5%
      \begin{tabularx}{\textwidth}{|X|r|}%
      #3\\\hline
      \end{tabularx}%
      #6%
      \end{table}%
    }%
    #4%
  }{%
    \expandafter\UD@PassThirdBeforeFirstToSecond\expandafter{%
      \romannumeral0%
      \UD@PassThirdBeforeTwiceExpandedFirstToSecond{%
        \UD@ExtractFirstArg{#1}%
      }{%
        \UD@SecondOfTwo{}%
      }{%
        \UD@CheckWhetherDigitTokensInRangeOnly
      }{1}{1}{%
        \expandafter\UD@CheckWhetherNull\expandafter{\UD@FirstOfTwo{}#1}{%
          \UD@Exchange{&x}%
        }{%
          \UD@Exchange{&x\\}%
        }%
      }{%
        \expandafter\UD@CheckWhetherNull\expandafter{\UD@FirstOfTwo{}#1}{%
          \UD@Exchange{&}%
        }{%
          \UD@Exchange{&\\}%
        }%
      }%
      {%
        \expandafter\expandafter
        \expandafter            \UD@Exchange
        \expandafter\expandafter
        \expandafter{%
        \UD@ExtractFirstArg{#2}}{ #3\hline}%
      }%
    }{%
      \expandafter\UD@PassThirdBeforeFirstToSecond\expandafter{%
        \UD@FirstOfTwo{}#2%
      }{%
        \expandafter\UD@PassThirdBeforeFirstToSecond\expandafter{%
          \UD@FirstOfTwo{}#1%
        }{%
          \UD@SecondOfTwo{}%
        }%
      }%
    }%
    {\TableRowsLoop}{#4}{#5}{#6}%
  }%
}%
%%//////////////////////////////////////////////////////////////////////////////
%% NON-GENERIC USER-LEVEL-MACROS
%%
%%==============================================================================
%% Error-message in case label but no caption
%%..............................................................................
%% \LabelWithoutCaptionError{<name of command which triggers the error-message>}%
%%                          {<syntax descriptor of caption argument>}%
%%                          {<syntax descriptor of label argument>}%
%%
%% The <syntax descriptors are to hold a phrase like "fifth non-optional".
%%==============================================================================
\newcommand\LabelWithoutCaptionError[3]{%
  \begingroup
  \GenericError{%
    \@backslashchar#1\space\space\space\@spaces\@spaces\@spaces
  }{%
   \@backslashchar#1-error\on@line: Referencing-label without caption%
  }{%
    See the comments of this file for explanation.%
  }{%
    The #2 argument of \@backslashchar#1 denotes a phrase that goes inside%
    \MessageBreak
    a \string\caption\space -command.%
    \MessageBreak
    The #3 argument of \@backslashchar#1 denotes a phrase that goes inside%
    \MessageBreak
    a \string\label\space -command.%
    \MessageBreak
    You specified an empty caption and a non-empty label.%
    \MessageBreak
    Usually it does not make sense to specifa a label without a sectioning
    \MessageBreak
    command like \string\caption\space or \string\section\space to refer to.%
  }%
  \endgroup
}%

%%==============================================================================
%% Automatic creation of a checklist-table for a specific set of parameters from 
%% - a comma-list with index-numbers denoting parameters 
%% - and a caption.
%%
%% That table comes as a table-environment holding a 
%% tabularx-environment and (in case the caption-argument is not empty) 
%% a caption.
%%..............................................................................
%% \mychecklist[<list of comma separated index-numbers>]%
%%             {<caption of the table>}%
%%             {<referencing label of the table>}%
%%
%% ( Due to \romannumeral0-expansion, the tokens that form the table and
%%   probably some error-messages  will be delivered after
%%   two expansion-steps/after having \mychecklistwithparameternames 
%%   "hit" via two \expandafter(-chains).  )
%%==============================================================================
\newcommand\mychecklist[3][1,3 , 5]{%
  \mychecklistwithparameternames{#1}{%
     {param 01}%
     {param 02}%
     {param 03}%
     {param 04}%
     {param 05}%
     {param 06}%
     {param 07}%
     {param 08}%
     {param 09}%
     {param 10}%
     {param 11}%
     {param 12}%
     {param 13}%
     {param 14}%
     {param 15}%
  }%
  {mychecklist}%
  {%
    \UD@CheckWhetherNull{#2}{%
      \UD@CheckWhetherNull{#3}{}{%
        \LabelWithoutCaptionError{mychecklist}%
                                 {first non-optional}%
                                 {second non-optional}%
      }%
    }{%
      \caption{#2}%
    }%
    \UD@CheckWhetherNull{#3}{}{\label{#3}}%
  }%
  {}%
}%
%%//////////////////////////////////////////////////////////////////////////////
\makeatother
%%//////////////////////////////////////////////////////////////////////////////
%% DOCUMENTCLASS AND ADDITIONAL PACKAGES:
%%
\documentclass{article}

\usepackage[colorlinks]{hyperref} % <- only used for demonstrating referencing.
\usepackage{tabularx}

\begin{document}

% Did you realize that \nameref automatically removes the full stop (.) at 
% the end of the sentence that forms the caption? ;-)

Refrence to
\hyperref[SplendidTableLabel]{table~\ref*{SplendidTableLabel}}
which has the caption
``\nameref{SplendidTableLabel}''.

Refrence to
\hyperref[MarvellousTableLabel]{table~\ref*{MarvellousTableLabel}}
which has the caption
``\nameref{MarvellousTableLabel}''.

Refrence to
\hyperref[TreeTableLabelA]{table~\ref*{TreeTableLabelB}}
which has the caption 
``\hyperref[TreeTableLabelA]{\nameref*{TreeTableLabelB}}''.

\mychecklist{A splendid table.}{SplendidTableLabel}% As default 1,3 and 5 are 
                                                  % checked.

\mychecklist[1, 2, 3, 4 ,5 , 6, ,7, 8 ,9, 10 , 11, 12, 13 , 14 , 15]%
            {A marvellous table.}{MarvellousTableLabel}%

\mychecklistwithparameternames{1, 4, 5}{%
   {Birch tree}% = parameter 1
   {Cedar}% = parameter 2
   {Chestnut}% = parameter 3
   {Oak}% = parameter 4
   {Cypress}% = parameter 5
   {Elm tree}% = parameter 6
   {Fir tree}% = parameter 7
   {Hazel-nut tree}% = parameter 8
   {Willow}% = parameter 9
   {Beech}% = parameter 10
   {Maple}% = parameter 11
   {Linden tree}% = parameter 12
   {Pine}% = parameter 13
   {Peach tree}% = parameter 14
   {Olive tree}% = parameter 15
   {Joshua tree}% = parameter 16
   {Sequoia}% = parameter 17
   {Cotton Wood tree}% = parameter 18
}{%
  mychecklistwithparameternames%
}{%
  {%
    \centering
    \large
    \textbf{%
      \phantomsection
      \label{TreeTableLabelA}% <- for the hyperref-anchor/destination.
      Please check the trees!%
    }%
    \par
  }%
  \bigskip
  \noindent
}{%
  \caption{A table for checking trees.}%
  \label{TreeTableLabelB}% <- for the textual phrases.
}%

\end{document}

在此处输入图片描述

在此处输入图片描述


由于 30,000 个字符的限制,我不得不将此答案分成四个部分。

这是我的答案的第四部分。

第1部分包括如何将事物划分为不同的子程序然后组合成所需机制的解释。

第2部分\usepackage由几个可以通过/加载的包文件/.sty 文件组成,\RequirePackage这些文件/文件附带一些所需的子程序。

第 3 部分\usepackage还包含几个可以通过/加载的包文件/.sty 文件\RequirePackage,这些文件带有一些所需的子程序。

第 4 部分提供一个 LaTeX 文档,该文档通过\RequirePackage/\usepackage加载包含所需子程序的包第2部分第 3 部分. 在该文档的头部,甚至在序言之前,这些子程序用于组合所需的通用和非通用用户级宏。

为了进行测试,请保存提供的包文件/.sty 文件第2部分第 3 部分以及text.tex来自第 4 部分在同一目录中并test.tex使用 LaTeX 引擎进行编译。

相关内容