我感觉这会非常简单,但我一直不知道如何去做。

考虑以下代码:

\documentclass{article}
\newcommand{\items}[2] {
\begin{itemize}
\item #1
\item #2
\end{itemize}
}
\begin{document}
\items{Foo}{Bar}
\end{document}

输出如下所示:

现在,假设参数 2 为空:

\documentclass{article}
\newcommand{\items}[2] {
\begin{itemize}
\item #1
\item #2
\end{itemize}
}
\begin{document}
\items{Foo}{}
\end{document}

不出所料,我们得到了这样的结果:

问题是,我怎样才能使第二项根本不出现,就像这样?

4

  • 内核有一个 IfEmptyTF,或者类似的东西,它在 usrguide.pdf 中,在办公室时会检查。否则来自 etoolbox 的 ifblank


    – 

  • 相关:


    – 


  • 2
    这个问题类似于:。如果您认为它有所不同,请问题,说明它有何不同和/或该问题的答案对您的问题无济于事。


    – 

  • 另请参阅\IfNoValueTFxparser 包,尽管它仅适用于可选参数。


    – 



最佳答案
4

您可以使用,\ifstrempty例如etoolbox

\documentclass{article}
\usepackage{etoolbox}
\newcommand{\items}[2] {
\begin{itemize}
\item #1
\ifstrempty{#2}{}{\item #2}%
\end{itemize}
}
\begin{document}
Foo:
\items{Foo1}{Foo2}
Bar:
\items{Bar1}{}
\end{document}

注意:\ifstrempty不扩展参数,并且像 中的空格\items{Foo}{ }不是空的。对于空或空格,您可以替换\ifstrempty\ifblank有关这些命令和类似命令的更多信息,请参阅文档)或较新的 LaTeX 内核命令(2022-06-01 或更新版本)\IfBlankTF

还有其他具有类似功能的软件包,例如scrbase

\documentclass{article}
\usepackage{scrbase}
\newcommand{\items}[2] {
\begin{itemize}
\item #1
\IfArgIsEmpty{#2}{}{\item #2}%
\end{itemize}
}
\begin{document}
\items{Foo1}{Bar1}
\items{Foo2}{}
\end{document}

scrbase还提供了\Ifstr扩展参数的函数。有关更多信息,请参阅

但是你也可以用可变数量的参数做一些棘手的事情:

\documentclass{article}
\newcommand{\items}{\begin{itemize}\processitems}
\makeatletter
\newcommand{\processitems}[1]{\item
  #1\@ifnextchar\bgroup{\processitems}{\end{itemize}}}
\makeatother
\begin{document}
Foo:
\items{Foo1}{Foo2}{Foo3}
Bar:
\items{Bar1}{Bar2}
Poo:
\items{Poo}
\end{document}

但因为这实际上并不像 LaTeX,所以您还可以对第 2、第 3、……第 n 个参数使用可变数量的可选参数:

\documentclass{article}
\newcommand{\items}{\begin{itemize}\processitems}
\NewDocumentCommand{\processitems}{mo}{
  \item #1
  \IfValueTF{#2}{\processitems{#2}}{\end{itemize}}
}
\begin{document}
Foo:
\items{Foo1}[Foo2][Foo3]
Bar:
\items{Bar1}[Bar2]
Poo:
\items{Poo}
\end{document}

结果和上面一样。

如果只需要两个参数,那么使用一个可选的而不是强制的第二个参数也是一个常见的解决方案:

\documentclass{article}
\NewDocumentCommand{\items}{mo}{%
  \begin{itemize}
  \item #1
  \IfValueT{#2}{\item #2}
  \end{itemize}
}
\begin{document}
Foo:
\items{Foo1}[Foo2]
Bar:
\items{Bar1}
\end{document}

对于只有两个参数{…}且第二个参数是可选的,您可以使用g仅在(已弃用的)包中可用的参数类型

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\items}{mg}{%
  \begin{itemize}
  \item #1
  \IfValueT{#2}{\item #2}
  \end{itemize}
}
\begin{document}
Foo:
\items{Foo1}{Foo2}
Bar:
\items{Bar1}
\end{document}

结果与上面相同。

1

  • 第一个就成功了。


    – 

就像 @daleif 在他的评论中提到的那样,您可以使用内核内置的检查来查看参数是否为空并采取相应措施。没有\IfEmptyTF,但您可以改用,\IfBlankTF如果参数仅包含空格,它也将为真。

\documentclass{article}
\newcommand{\items}[2]{%
  \begin{itemize}%
    \item #1%
    \IfBlankF{#2}{\item #2}%
  \end{itemize}%
}
\begin{document}
\items{Foo}{}
\end{document}

另一个版本以 LaTeX 友好的语法接受任意多项:

\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand \items { m }
  {
    \begin{itemize}
      \tl_map_function:nN {#1} \item
    \end{itemize}
  }
\ExplSyntaxOff
\begin{document}
Single item is harder: \items{{Foo}}

Multiple items is simple and very flexible: \items{{Foo}{Bar}{Baz}}
\end{document}

7

  • 当我尝试使用 进行编译时pdflatex,失败了! Undefined control sequence. \items #1#2->\begin {itemize}\item #1\IfBlankF {#2}{\item #2}\end {itemize} l.9 \items{Foo}{}


    – 

  • @KristianNordestgaard – 您使用的是哪个 TeX 发行版,上次更新是什么时候?我之所以问这个问题,是因为答案在我的 TeXLive2024 发行版(安装了所有更新)上可以顺利运行。


    – 

  • @Mico pdfTeX 3.141592653-2.6-1.40.23 (TeX Live 2021)


    – 

  • 2
    @KristianNordestgaard 对于\IfBlankTF,,您至少需要 LaTeX 2022-06-01。对于较旧的 LaTeX 内核,您可以使用\IfBlankT我的答案。\IfBlankFetoolbox


    – 

  • 2
    @KristianNordestgaard 你可以\ExplSyntaxOn\cs_new_eq:NN \IfBlankF \tl_if_blank:nF\ExplSyntaxOff在 TL 2021 的序言中使用它,答案应该有效。


    – 

简单的:

\newcommand{\items}[2]{%
  \begin{itemize}
  \item #1 \if\relax\detokenize{#2}\relax\else\item #2\fi
  \end{itemize}
}

接下来,如何对三个或更多项目执行相同操作?如果超出了九个允许的参数,该怎么办?

让我们更笼统一点。你必须用参数列表做一些事情,这些参数可以是从零到任意数字。例如,建立一个逐项列表(或枚举列表,或gather一堆公式)。

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\processarguments}{mmmO{}m}
 {% #1 = pre, #2 = post, #3 = template, #4 = separator, #5 = list of items
  \nordestgaard_processargs:nnnnn {#1} {#2} {#3} {#4} {#5}
 }

\seq_new:N \l__nordestgaard_processargs_items_seq
\cs_new_protected:Nn \__nordestgaard_processargs_do:n {}

\cs_new_protected:Nn \nordestgaard_processargs:nnnnn
 {
  % populate the sequence
  \seq_clear:N \l__nordestgaard_processargs_items_seq
  \tl_map_inline:nn {#5}
   {
    \seq_put_right:Nn \l__nordestgaard_processargs_items_seq
     {% we want to apply the template on the items
      \__nordestgaard_processargs_do:n {##1}
     }
   }
  % define the processing command to the template
  \cs_set_protected:Nn \__nordestgaard_processargs_do:n {#3}
  % issue the 'pre' tokens
  #1
  % use the sequence
  \seq_use:Nn \l__nordestgaard_processargs_items_seq {#4}
  % issue the 'post' tokens
  #2
 }

\ExplSyntaxOff

\begin{document}

One item
\processarguments{\begin{itemize}}{\end{itemize}}{\item #1}{
  {Foo}
}

Two items
\processarguments{\begin{itemize}}{\end{itemize}}{\item #1}{
  {Foo}
  {Bar}
}

Three items
\processarguments{\begin{enumerate}}{\end{enumerate}}{\item #1}{
  {Foo}
  {Bar}
  {Again!}
}

We can gather formulas
\processarguments{\begin{gather}}{\end{gather}}{#1}[\\]{
  {(a+b)+c=a+(b+c)}
  {x+y=y+x}
  {xy=yx}
}

\end{document}

当然,您可以在此基础上进行构建,并将您的\items命令定义为

\newcommand{\items}[1]{%
  \processarguments{\begin{itemize}}{\end{itemize}}{\item ##1}{#1}%
}

请注意,##1因为我们在定义里面。

或者更好的是,请参阅下面的代码。

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\processarguments}{mmmO{}m}
 {% #1 = pre, #2 = post, #3 = template, #4 = separator, #5 = list of items
  \nordestgaard_processargs:nnnnn {#1} {#2} {#3} {#4} {#5}
 }

\seq_new:N \l__nordestgaard_processargs_items_seq
\cs_new_protected:Nn \__nordestgaard_processargs_do:n {}

\cs_new_protected:Nn \nordestgaard_processargs:nnnnn
 {
  % populate the sequence
  \seq_clear:N \l__nordestgaard_processargs_items_seq
  \tl_map_inline:nn {#5}
   {
    \seq_put_right:Nn \l__nordestgaard_processargs_items_seq
     {% we want to apply the template on the items
      \__nordestgaard_processargs_do:n {##1}
     }
   }
  % define the processing command to the template
  \cs_set_protected:Nn \__nordestgaard_processargs_do:n {#3}
  % issue the 'pre' tokens
  #1
  % use the sequence
  \seq_use:Nn \l__nordestgaard_processargs_items_seq {#4}
  % issue the 'post' tokens
  #2
 }

\ExplSyntaxOff

%%% now we define a few instances
% first your \items
\NewDocumentCommand{\items}{m}{%
  \processarguments{\begin{itemize}}{\end{itemize}}{\item ##1}{#1}%
}
% next a better one
\NewDocumentCommand{\xitems}{O{itemize}m}{%
  \processarguments{\begin{#1}}{\end{#1}}{\item ##1}{#2}%
}

\begin{document}

One item
\items{
  {Foo}
}

Two items
\items{
  {Foo}
  {Bar}
}

Three items
\xitems[enumerate]{
  {Foo}
  {Bar}
  {Again!}
}

\end{document}

使用此语法,输入只需要多两个括号,但可以容纳任意数量的项目。

在 TeX 原始级别测试参数是否为空的传统方法是,\ifx ?#1?并且您必须假设?永远不会作为的第一个标记出现#1。如果#1为空,则测试简化为\ifx ??,这是正确的,因为“?”等于“?”。如果#1不为空(例如#1abc),则测试看起来像\ifx ?abc?,并且因为?不等于,所以a跳过以下文本,直到\else达到\fi

在您的示例中,项目文本永远不会以 开头,^因为此标记仅在数学模式下使用。因此,您的测试应该是:

\documentclass{article}
\newcommand{\items}[2] {
\begin{itemize}
\item #1
\ifx ^#2^\else \item #2\fi
\end{itemize}
}
\begin{document}
\items{Foo}{}
\end{document}

如果您想要实现的通用可扩展测试为#1空,请使用\if^\detokenize{#1}^\if原语会扩展\detokenize并将所有标记转换为 catcode 12(或空格为 10),因此 catcode 为 7 的标记^永远不会是\detokenize输出的第一个标记。

0