如何使用 \@ifnextchar 创建“引用表”宏?

如何使用 \@ifnextchar 创建“引用表”宏?

我需要在大型政策手册的每个部分的底部添加一个程序手册的参考表,如下所示:

\begin{table}[H]
\begin{tabular}{ |c|c| } 
  \hline
  \multicolumn{2}{|c|}{Procedures} \\
  \hline
  %fyi PM = Procedures Manual
  PM \ref{PM-tyinglaces} & \nameref{PM-tyinglaces} \\ 
  PM \ref{PM-polishshoes & \nameref{PM-polishshoes} \\
  PM \ref{PM-ironshirt} & \nameref{PM-ironshirt} \\
  \hline
\end{tabular}
\end{table}

当然,由于每个表的格式都相同,我真的很想要一个具有类似语法的宏:

%\procedurelist{firstlabel}{nextlabel}...{nthlabel}
%
\procedurelist{PM-tyinglaces}{PM-polishshoes}{PM-ironshirt}

单个逗号分隔的参数也可以。我的尝试如下。我就是无法让它关闭表格,不知何故,当我包含结束 \hline 时它​​会中断。

\makeatletter
\newcommand{\procedurelist}[1]{%
    \begin{table}[H]
    \begin{tabular}{ |c|c| } 
    \hline
    \multicolumn{2}{|c|}{Procedures} \\
    \hline
    PM \ref{#1} & \nameref{#1} \\%
    \checknextarg
}
\newcommand{\checknextarg}{%
    \@ifnextchar\bgroup{%
        \consumenextarg
    }{%
        \hline  %causes error?
        \end{tabular}
        \end{table}
    }
}
\newcommand{\consumenextarg}[1]{%
    PM \ref{#1} & \nameref{#1} \\%
    \@ifnextchar\bgroup{%
        \consumenextarg
    }{%
        \hline %causes error?
        \end{tabular}
        \end{table}
    }
}
\makeatother

我如何实现我的目标?

我的宏中做错了什么?

答案1

我不建议使用如下语法

\procedurelist{a}{b}{c}...{z}

更喜欢类似的东西

\procedurelist{a,b,c,...,z}

其实按照你想象的那样去做并不难,诀窍在于提前搭建好桌体。

\documentclass{article}
\usepackage{hyperref}

\makeatletter
\newcommand{\procedurelist}{%
  \proclist@body={}%
  \proclist@start
}

\newtoks\proclist@body
\newcommand{\proclist@start}{%
  \@ifnextchar\bgroup\proclist@absorb\proclist@finish
}
\newcommand{\proclist@absorb}[1]{%
  \proclist@body=\expandafter{%
    \the\proclist@body
    PM~\ref{#1} & \nameref{#1} \\%
  }%
  \proclist@start
}
\newcommand{\proclist@finish}{%
  \begin{tabular}{|c|c|}
  \hline
  \the\proclist@body
  \hline
  \end{tabular}%
}
\makeatother

\begin{document}

\section{Tie laces}\label{PM-tyinglaces}
\section{Polish shoes}\label{PM-polishshoes}
\section{Iron shirt}\label{PM-ironshirt}

\section{End}

\procedurelist{PM-tyinglaces}{PM-polishshoes}{PM-ironshirt}

\end{document}

使用逗号分隔列表的另一种方法更容易expl3,因为它已经具有处理逗号分隔列表和循环它们的功能。

\documentclass{article}
\usepackage{xparse}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand{\procedurelist}{m}
 {
  \seq_clear:N \l__kjc_procedurelist_seq
  \clist_map_inline:nn { #1 }
   {
    \seq_put_right:Nn \l__kjc_procedurelist_seq
     {
      PM~\ref{##1} & \nameref{##1}
     }
   }
  \begin{tabular}{|c|c|}
  \hline
  \seq_use:Nn \l__kjc_procedurelist_seq { \\ } \\
  \hline
  \end{tabular}
 }

\seq_new:N \l__kjc_procedurelist_seq

\ExplSyntaxOff

\begin{document}

\section{Tie laces}\label{PM-tyinglaces}
\section{Polish shoes}\label{PM-polishshoes}
\section{Iron shirt}\label{PM-ironshirt}

\section{End}

\procedurelist{PM-tyinglaces,PM-polishshoes,PM-ironshirt}  

\end{document}

在此处输入图片描述

更好的表格:

\documentclass{article}
\usepackage{xparse,booktabs}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand{\procedurelist}{m}
 {
  \seq_clear:N \l__kjc_procedurelist_seq
  \clist_map_inline:nn { #1 }
   {
    \seq_put_right:Nn \l__kjc_procedurelist_seq
     {
      \ref{##1} & \nameref{##1}
     }
   }
  \begin{tabular}{cl}
  \toprule
  \multicolumn{1}{c}{\textbf{PM}} & \textbf{Name} \\
  \midrule
  \seq_use:Nn \l__kjc_procedurelist_seq { \\ } \\
  \bottomrule
  \end{tabular}
 }

\seq_new:N \l__kjc_procedurelist_seq

\ExplSyntaxOff

\begin{document}

\section{Tie laces}\label{PM-tyinglaces}
\section{Polish shoes}\label{PM-polishshoes}
\section{Iron shirt}\label{PM-ironshirt}

\section{End}

\procedurelist{PM-tyinglaces,PM-polishshoes,PM-ironshirt}  

\end{document}

在此处输入图片描述

一旦掌握了窍门,就可以更简单地实现它:

\documentclass{article}
\usepackage{xparse,booktabs}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand{\procedurelist}{m}
 {
  \cs_set:Nn \__kjc_procedurelist_row:n { \ref{##1} & \nameref{##1} \\ }
  \begin{tabular}{cl}
  \toprule
  \multicolumn{1}{c}{\textbf{PM}} & \textbf{Name} \\
  \midrule
  \clist_map_function:nN { #1 } \__kjc_procedurelist_row:n
  \bottomrule
  \end{tabular}
 }

\ExplSyntaxOff

\begin{document}

\section{Tie laces}\label{PM-tyinglaces}
\section{Polish shoes}\label{PM-polishshoes}
\section{Iron shirt}\label{PM-ironshirt}

\section{End}

\procedurelist{PM-tyinglaces,PM-polishshoes,PM-ironshirt}  

\end{document}

通过这种方法,\__kjc_procedurelist_row:n可以在主命令之外定义函数。但是,也可以通过允许动态更改默认值来改进这一点:

\documentclass{article}
\usepackage{xparse,booktabs}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand{\procedurelist}{om}
 {
  \IfValueT{#1}
   {
    \cs_set:Nn \__kjc_procedurelist_row:n { #1 }
   }
  \begin{tabular}{cl}
  \toprule
  \multicolumn{1}{c}{\textbf{PM}} & \textbf{Name} \\
  \midrule
  \clist_map_function:nN { #2 } \__kjc_procedurelist_row:n
  \bottomrule
  \end{tabular}
 }
\cs_new:Nn \__kjc_procedurelist_row:n { \ref{#1} & \nameref{#1} \\ }
\ExplSyntaxOff

\begin{document}

\section{Tie laces}\label{PM-tyinglaces}
\section{Polish shoes}\label{PM-polishshoes}
\section{Iron shirt}\label{PM-ironshirt}

\section{End}

\procedurelist{
  PM-tyinglaces,
  PM-polishshoes,
  PM-ironshirt
}
\procedurelist[\ref{#1} & \textit{\nameref{#1}} \\]{
  PM-tyinglaces,
  PM-polishshoes,
  PM-ironshirt
}

\end{document}

在此处输入图片描述

答案2

诀窍是首先获取所有这些参数并将它们存储在某个地方(此处\procedurelist@content)。获取所有参数后,您就可以输出格式化的表格。这样,表格内部就不会有任何无法扩展的测试阻止任何\noaligns。

示例代码(我删除了\namerefs 和周围的内容,因为如果唯一允许的位置是并且您不使用标题,table那么这没有意义):H

\documentclass[]{article}

\makeatletter
\newcommand*\procedurelist@content{}
\newcommand*\procedurelist@checknext
  {%
    \@ifnextchar\bgroup
      {\procedurelist@eatnext}
      {\procedurelist@shipout}%
  }
\newcommand\procedurelist[1]
  {%
    \begingroup
    \def\procedurelist@content{PM \ref{#1} & #1 \\}%
    \procedurelist@checknext
  }
\newcommand\procedurelist@eatnext[1]
  {%
    \edef\procedurelist@content
      {\unexpanded\expandafter{\procedurelist@content PM \ref{#1} & #1 \\}}%
    \procedurelist@checknext
  }
\newcommand*\procedurelist@shipout
  {%
    \begin{tabular}{|c|c|}
      \hline
      \multicolumn{2}{|c|}{Procedures} \\
      \hline
      \procedurelist@content
      \hline
    \end{tabular}%
    \endgroup
  }
\makeatother

\begin{document}
\procedurelist{arg1}{arg2}{arg3}{arg4}
\end{document}

在此处输入图片描述

答案3

使用\xintFor(这不是可扩展循环,但仍然可以在表格中工作......)

\documentclass{article}
\usepackage{booktabs}
\usepackage{hyperref}
\usepackage{xinttools}

\newcommand{\procedurelist}[1]{%
  \begin{tabular}{cl}
  \toprule
  \multicolumn{1}{c}{\textbf{PM}} & \textbf{Name} \\
  \midrule
  \xintFor ##1 in {#1}\do {\ref{##1} & \nameref{##1} \\ }
  \bottomrule
  \end{tabular}
}

\begin{document}

\section{Tie laces}\label{PM-tyinglaces}
\section{Polish shoes}\label{PM-polishshoes}
\section{Iron shirt}\label{PM-ironshirt}

\section{End}

\procedurelist{PM-tyinglaces,PM-polishshoes,PM-ironshirt}  

\end{document}

在此处输入图片描述

相关内容