使用 \foreach 循环执行宏,宏的参数以列表形式提供

使用 \foreach 循环执行宏,宏的参数以列表形式提供

我需要多次执行宏,并希望提供要执行的参数列表。因此,

\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

我更愿意简单地设置一个列表:

\DefineMyFormatLinkParameters{%
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com},
}

然后执行该列表的每个元素的\FormatLinks\foreach。我认为这可能是一些与扩展相关的问题,但我无法让它工作。目前,输出为:

在此处输入图片描述

代码:

\documentclass{article}
\usepackage{url}
\usepackage{pgffor}
\usepackage{xparse}
\usepackage{xstring}
\usepackage[colorlinks=true]{hyperref}

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    O{}% #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
    \par
    \IfStrEq{#2}{}{%
        \hspace*{1.0cm}\href{#4}{#3}%
    }{%
        \hspace*{1.0cm}\href{#4}{#3~(#2)}%
    }%
}%

\newcommand*{\MyFormatLinkParameters}{}% Initialize
\newcommand*{\DefineMyFormatLinkParameters}[1]{%
    \edef\MyFormatLinkParameters{#1}%
}%

\begin{document}
\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

% Would prefer to define a list, and later execute the list:
\DefineMyFormatLinkParameters{%
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com},
}

\bigskip% 
Following should produce same results as above:\medskip\par
\foreach \x in \MyFormatLinkParameters {%
    \typeout{DEBUG: "\x"}
    \FormatLinks{\x}
}

\end{document}

答案1

这里有两点错误:

  1. 应该进行的扩展\x,而不是将其作为单个参数传递给\FormatLinks

    因此,

    \FormatLinks{\x}
    

    使用

    \expandafter\FormatLinks\x
    

    \x因为这会在输入流中留下一个扩展空间以\FormatLinks供吞噬。

  2. 列表中有一个空项(最后一项);

    空列表项意味着当你传递\x\FormatLinks它时期望至少两个参数,但它没有收到任何参数。所以它会吞噬所有收到的参数,这显然是做错了。

在此处输入图片描述

\documentclass{article}
\usepackage{url}
\usepackage{pgffor}
\usepackage{xparse}
\usepackage{xstring}
\usepackage[colorlinks=true]{hyperref}

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    O{}% #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
    \par
    \IfStrEq{#2}{}{%
        \hspace*{1.0cm}\href{#4}{#3}%
    }{%
        \hspace*{1.0cm}\href{#4}{#3~(#2)}%
    }%
}%

\newcommand*{\MyFormatLinkParameters}{}% Initialize
\newcommand*{\DefineMyFormatLinkParameters}[1]{%
    \edef\MyFormatLinkParameters{#1}%
}%

\begin{document}
\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

% Would prefer to define a list, and later execute the list:
\DefineMyFormatLinkParameters{%
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com}
}

\bigskip% 
Following should produce same results as above:\medskip\par
\foreach \x in \MyFormatLinkParameters {%
    \typeout{DEBUG: "\x"}
    \expandafter\FormatLinks\x
}

\end{document}

答案2

\IfStr{#2}{}既然xparse已经提供了基础设施,为什么还要这么神秘呢?

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    o%   #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
  \par
  \hspace*{1.0cm}\href{#4}{#3\IfValueT{#2}{~#2}}%
}

问题是你想做\FormatLinks{\x},但想在看到\x之前展开\FormatLinks;然而括号不应该在那里。所以\expandafter\FormatLinks\x会这样做。

更好的是,使用一个 clist 和一个映射函数。

\documentclass{article}
\usepackage{url}
\usepackage{xparse}
\usepackage[colorlinks=true]{hyperref}

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    o%   #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
  \par
  \hspace*{1.0cm}\href{#4}{#3\IfValueT{#2}{~#2}}%
}

\ExplSyntaxOn
\NewDocumentCommand{\FormatLinksList}{}
 {
  \clist_map_inline:Nn \g_grill_linkparameters_clist { \FormatLinks ##1 }
 }
\NewDocumentCommand{\DefineMyFormatLinkParameters}{m}
 {
  \clist_gset:Nn \g_grill_linkparameters_clist { #1 }
 }
\ExplSyntaxOff

\begin{document}
\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

% Would prefer to define a list, and later execute the list:
\DefineMyFormatLinkParameters{
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com},
}

\bigskip

Following should produce same results as above:\medskip\par

\FormatLinksList

\end{document}

在此处输入图片描述

相关内容