如何遍历所有用户定义的控制字?

如何遍历所有用户定义的控制字?
\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}

名称迭代

相关内容