N 个开关(选择器/条件/切换)来处理邮件列表

N 个开关(选择器/条件/切换)来处理邮件列表

假设我想给 10 个人寄同一封信。除了收件人的姓名和地址外,信件内容应该相同。

此外,我想附上所有其他我向其发送了这封信的人员。

我知道我可以将多个toggle使用组合起来etoolbox,但没有更简单的方法吗?

\documentclass{article}

\usepackage{etoolbox}

\newtoggle{A1}
\newtoggle{A2}
\newtoggle{A3}
% Etc.
\newtoggle{A10}

\toggletrue{A1}

\togglefalse{A2}
\togglefalse{A3}
%Etc.
\togglefalse{A10}

\iftoggle{A1}{
    \def\name{Toto}
    \def\adress{That Street}
    }
    {\iftoggle{A2}{
        \def\name{Tata}
        \def\adress{This Street}
    }
            {\iftoggle{A3}{
            %Etc.
            }
        }
    }

\begin{document}

Dear \name, 

please find below the name of the other recipients:
\begin{itemize}
\item Tata,
% Print the name of A2 -> A10 in that case.
\item Titi
\end{itemize}
\end{document}

我不介意只需进行轻微的更改即可编译 10 倍的文档,但我并不反对编写某些脚本。

答案1

每个新收件人都会按顺序插入,作为映射的基础;姓名和地址将被放入属性列表中。

信件的文字作为参数给出,\printletter该参数循环遍历信件内部的序列项目,\name\address扩展到当前收件人,同时\cc将打印所有其他收件人姓名的逐项列表。

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newrecipient}{mm}
 {% #1 = name, #2 = address
  \clement_new_recipient:nn { #1 } { #2 }
 }

\NewDocumentCommand{\name}{}
 {
  \prop_item:Nf \g_clement_recipients_prop { \l_clement_current_recipient_tl @ name }
 }

\NewDocumentCommand{\address}{}
 {
  \prop_item:Nf \g_clement_recipients_prop { \l_clement_current_recipient_tl @ address }
 }

\NewDocumentCommand{\cc}{}
 {
  \clement_cc_list:
 }

\NewDocumentCommand{\printletter}{+m}
 {
  \seq_map_inline:Nn \g_clement_recipients_seq
   {
    \tl_set:Nn \l_clement_current_recipient_tl { ##1 }
    #1
    \clearpage
   }
 }

\seq_new:N \g_clement_recipients_seq
\prop_new:N \g_clement_recipients_prop
\tl_new:N \l_clement_current_recipient_tl

\cs_generate_variant:Nn \prop_gput:Nnn { Nfn }
\cs_generate_variant:Nn \prop_item:Nn { Nf }
\cs_generate_variant:Nn \tl_if_eq:nnF { V }

\cs_new_protected:Npn \clement_new_recipient:nn #1 #2
 {
  \seq_gput_right:Nx \g_clement_recipients_seq { \tl_to_str:n { #1 } }
  \prop_gput:Nfn \g_clement_recipients_prop
   { \tl_to_str:n { #1 } @ name } { #1 }
  \prop_gput:Nfn \g_clement_recipients_prop
   { \tl_to_str:n { #1 } @ address } { #2 }
 }

\cs_new_protected:Npn \clement_cc_list:
 {
  \begin{itemize}
  \seq_map_inline:Nn \g_clement_recipients_seq
   {
    \tl_if_eq:VnF \l_clement_current_recipient_tl { ##1 }
     {
      \item \prop_item:Nf \g_clement_recipients_prop { ##1 @ name }
     }
   }
  \end{itemize}
 }

\ExplSyntaxOff

\newrecipient{Toto}{That Street\\Town}
\newrecipient{Tata}{This Street\\Village}
\newrecipient{T\'et\'e}{Another Place}

\begin{document}

\printletter{
  \hspace*{\fill}%
  \begin{tabular}{l@{}}
  \name \\
  \address
  \end{tabular}

\bigskip

Here, \today

\bigskip
\bigskip

Dear \name,\\
here is my letter to you and to other people that
you'll find listed at the bottom. Some other words
in order to fill some lines.

\bigskip

Sincerely yours

A. Uthor

\bigskip

\cc

}

\end{document}

当然,复杂的代码将存储在外部文件中\input,因此它是可重复使用的,并且不会破坏主文档。

显示的打印输出使用规则而不是\clearpage代码中的,以便仅填充一页。

在此处输入图片描述

答案2

这利用了这样一个事实:可以定义\def宏并为参数添加分隔符,比如/斜线,用于分隔name/address

\RegisterNames调用此拆分宏并将姓名和地址存储到单独的列表中,然后使用迭代命令生成信件(不包括收件人列表中的当前姓名)

编辑

改良版

\documentclass{article}

\usepackage{xstring}
\usepackage{etoolbox}

\def\nameaddresslist{}%
\def\namelist{}%
\def\addresslist{}%

% Helper macro
\makeatletter
\def\@splitmylist#1/#2\@nil{%
\listgadd{\namelist}{#1}%
\listgadd{\addresslist}{#2}%
\stepcounter{numnames}%
}


% Wrapper macro for actual splitting
\newcommand{\splitmylist}[1]{\@splitmylist#1\@nil}
\makeatother


\newcounter{numnames}%
\newcounter{tempcounter}%
\newcounter{loopcounter}%

% Get the address of entry number #1 in list #2
\newcommand{\getaddress}[2]{%
  \begingroup % Important, since \do is redefined
  \setcounter{tempcounter}{0}%
  \renewcommand*{\do}[1]{%
    \stepcounter{tempcounter}%
    \ifnumequal{\value{tempcounter}}{#1}{%
      ##1\listbreak%
    }{%
    }%
  }%
  \dolistloop{#2}%
  \endgroup
}

\newcommand{\iteratenames}[2]{%
\setcounter{loopcounter}{0}
Dear #2, 

please find below the name and address of the other recipients:
\begin{itemize}
\renewcommand*{\do}[1]{%
  \stepcounter{loopcounter}
  \IfStrEq{#2}{##1}{%
    }{%  Printing the other names and their address
    \item ##1 (\getaddress{\value{loopcounter}}{\addresslist})%
    }%
}%
\dolistloop{#1}%
\end{itemize}

% Only for demo purposes
\vskip\baselineskip
\hrule
\vskip\baselineskip


}


\newcommand{\RegisterNames}[1]{%
\forcsvlist{\splitmylist}{#1}
}

\begin{document}
\RegisterNames{Gandalf/{Gondor, Palace},Arwen/Rivendel,Frodo/Shire,Sauron/Mordor,Thorin/Erebor,Balin/Moria}

% Show list
\forlistloop{\iteratenames{\namelist}}{\namelist} % Could be packed into a command too
\end{document}

在此处输入图片描述

相关内容