\documentclass[preview,border=12pt,varwidth]{standalone}
\usepackage{pgffor}
\def\Person#1{%
\ifcsname#1\endcsname
\else
\expandafter\def\csname #1\endcsname{#1}%
\fi
\csname#1\endcsname
}
\begin{document}
\Person{Alan} took a shower when
\Person{Batman} was cooking in the
\Person{Carlisle}'s house which lies 3 meter due east of
\Person{David}'s school or 4 meter due west of
\Person{Enrico}'s office.
How can I iterate through the persons mentioned in the first paragraph?
\end{document}
如何遍历所有用户定义的控制字而不使用\foreach
宏并手动列出名称?
答案1
任何列表处理包应该能够处理这个问题。我最熟悉的是etoolbox
, 尽管 LaTeX3 也有一些易于使用的功能。
\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\PersonList}{}% Declare list
\newcommand{\Person}[1]{%
\ifinlist{#1}{\PersonList}% \ifinlist{<item>}{<list>}
{}% <true>
{\listgadd{\PersonList}{#1}}% <false>
#1% Print Person
}
\newcommand{\PrintPersons}{% Whatever you want to do with the list...
\def\insertgap{\def\insertgap{ }}% http://tex.stackexchange.com/a/89187/5764
\forlistloop{\insertgap}{\PersonList}}% Process list
\begin{document}
\Person{Alan} took a shower when \par
\Person{Batman} was cooking in the \par
\Person{Carlisle}'s house which lies 3 meter due east of \par
\Person{David}'s school or 4 meter due west of \par
\Person{Enrico}'s office.
How can I iterate through the persons mentioned in the first paragraph? \par
\PrintPersons
\end{document}
答案2
普通 TeX,只是为了改变(没有 e-TeX)。
\def\PersonList{}
\def\Person#1{%
\expandafter\ifx\csname#1@Listed\endcsname\relax
\expandafter\let\csname#1@Listed\endcsname\empty
\expandafter\def\expandafter\PersonList\expandafter{\PersonList\doPerson{#1}}%
\fi
#1%
}
\def\doPerson#1{#1 was listed\par}
\Person{Alan} took a shower when
\Person{Batman} was cooking in the
\Person{Carlisle}'s house which lies 3 meter due east of
\Person{David}'s school or 4 meter due west of
\Person{Enrico}'s office.
\bigskip
\PersonList
\bye
现在有了 LaTeX3 版本,其中\PersonList
函数需要一个可选参数来为列出的每个人执行。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\Person}{m}
{
\egreg_addperson:n { #1 }
}
\NewDocumentCommand{\PersonList}{O{\doPersonDefault}}
{
\egreg_listpersons:N #1
}
\NewDocumentCommand{\doPersonDefault}{m}
{
#1~was~listed\par
}
\seq_new:N \g_egreg_persons_seq
\cs_new_protected:Npn \egreg_addperson:n #1
{
\seq_if_in:NnF \g_egreg_persons_seq { #1 }
{
\seq_gput_right:Nn \g_egreg_persons_seq { #1 }
}
#1
}
\cs_new_protected:Npn \egreg_listpersons:N #1
{
\seq_map_function:NN \g_egreg_persons_seq #1
}
\ExplSyntaxOff
\newcommand{\doPerson}[1]{Yes, #1 was listed, what else?\par}
\begin{document}
\Person{Alan} took a shower when
\Person{Batman} was cooking in the
\Person{Carlisle}'s house which lies 3 meter due east of
\Person{David}'s school or 4 meter due west of
\Person{Enrico}'s office.
\bigskip
\PersonList
\bigskip
\PersonList[\doPerson]
\end{document}
答案3
根据我的评论马可·丹尼尔的评论,但我不确定我是否正确理解了这个问题。
\documentclass[preview,border=12pt,varwidth]{standalone}
\usepackage{pgffor}
\let\PersonList\empty
\def\Person#1{%
\ifcsname#1\endcsname
\else
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\PersonList
\expandafter\expandafter\expandafter
{\expandafter\PersonList\expandafter{\csname #1\endcsname}}%
\expandafter\def\csname #1\endcsname{#1}%
\fi
\csname#1\endcsname
}
\begin{document}
\Person{Alan} took a shower when
\Person{Batman} was cooking in the
\Person{Carlisle}'s house which lies 3 meter due east of
\Person{David}'s school or 4 meter due west of
\Person{Enrico}'s office.
How can I iterate through the persons mentioned in the first paragraph?
\texttt{\meaning\PersonList}
\end{document}