![使用 \foreach 循环执行宏,宏的参数以列表形式提供](https://linux22.com/image/309511/%E4%BD%BF%E7%94%A8%20%5Cforeach%20%E5%BE%AA%E7%8E%AF%E6%89%A7%E8%A1%8C%E5%AE%8F%EF%BC%8C%E5%AE%8F%E7%9A%84%E5%8F%82%E6%95%B0%E4%BB%A5%E5%88%97%E8%A1%A8%E5%BD%A2%E5%BC%8F%E6%8F%90%E4%BE%9B.png)
我需要多次执行宏,并希望提供要执行的参数列表。因此,
\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
这里有两点错误:
应该进行的扩展
\x
,而不是将其作为单个参数传递给\FormatLinks
。因此,
\FormatLinks{\x}
使用
\expandafter\FormatLinks\x
\x
因为这会在输入流中留下一个扩展空间以\FormatLinks
供吞噬。列表中有一个空项(最后一项);
空列表项意味着当你传递
\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}