LaTex: Automating Repetition

Few days ago, a buddy of mine contacted me with a problem. He was tasked with creating about a thousand form letters (for snail mail distribution). Being an awesome dude, he turned to open source solutions – and specifically LaTex rather than braving the evils of Mail Merge in Microsoft Word. He correctly guessed that this tool could easily take a delimited list of addresses and generate the right number of letters without much hassle. He however was a bit at a loss on how to actually implement it.

Being a bit of a problem solver I decided to jump in and help him out. His letter went a little bit like this:

\documentclass{letter}
\begin{document}
\clearpage 

\signature{John Smith}
\address{
Bouncing Shuttlecocks Incorporated \\ 
1234 Squiggly Bottom Court \\ 
Hoffenpuff, AL 12348\\ 
contact@bouncingshuttlecocks.us}

\begin{letter}{Mr. Poop McGee \\ Some Address \\ Some City, NJ, 07586}
\opening{Dear Sir or Madam:}

We would like to send you a sample of our terrific product for free, 
so that you can see that our shuttlecocks bounce the best. 

If you are not satisfied with bounciness of our shuttlecocks we are 
prepared to send you another sample for free just so you can re-evaluate 
it. And then another one if that one is not bouncy to your liking either. 
In fact, we will just keep sending you free samples until you agree that 
the bounciness factor of our shuttlecocks is satisfactory. We will drown 
you in free shuttlecocks! Don't even try returning them to sender - we 
know people at UPS.

So please evaluate our sample and let us know how much you enjoyed the 
bounciness of our shuttlecocks.

\closing{We look forward to hearing from you,}
\end{letter}
\clearpage 
\end{document}

There would be only one line in this letter that would change – the Poop McGee line. That’s ideally where he would want to plug different addresses from a list. But how?

Well, I did a little bit of research and found out that the easiest way to accomplish this is by using a nice package called forarray. It ships with a ForEach command which has the following syntax:

\ForEach
{;}                % delimiter
{ \thislevelitem } % function
{ foo; bar; baz }  % list

The delimiter is exactly what it sounds – a character (or series of characters) that will separate items on your list. As you can see, the list I used in the third bracket uses the semicolon delimiter defined in the first one. This command will iterate over that list and output whatever it is you put in the middle bracket. In this particular case the only thing I’m outputting is \thislevelitem which is the “current” list item. So the output of this particular code would simply be: foo bar baz. Of course you can put whatever you want in that middle bracket. For example, the text of our letter.

Here is how you would apply this to generate bunch of form letters like the one above:

\documentclass{letter}
\usepackage{forarray}
\begin{document}

\ForEach {;}
{

\clearpage 
\signature{John Smith}
\address {
Bouncing Shuttlecocks Incorporated \\ 
1234 Squiggly Bottom Court \\ 
Hoffenpuff, AL 12348\\ 
contact@bouncingshuttlecocks.us}

\begin{letter}{\thislevelitem}
\opening{Dear Sir or Madam:}

We would like to send you a sample of our terrific product for free, 
so that you can see that our shuttlecocks bounce the best. 

If you are not satisfied with bounciness of our shuttlecocks we are 
prepared to send you another sample for free just so you can re-evaluate 
it. And then another one if that one is not bouncy to your liking either. 
In fact, we will just keep sending you free samples until you agree that 
the bounciness factor of our shuttlecocks is satisfactory. We will drown 
you in free shuttlecocks! And don't even try returning them to sender - 
we know people at UPS.

So please evaluate our sample and let us know how much you enjoyed the 
bounciness of our shuttlecocks.

\closing{We look forward to hearing from you,}
\end{letter}
\clearpage 

}
{
Ms. Jane Smith \\ Foobar Incorporated\\ Foo Street \\ Foo City, GA 44559; 
Mr. Poop McGee \\ Some Company \\ Some Street \\ Some City, IL 112547; 
Mr. Nobody \\ No Company \\ No Street \\ No Town TX, 586235
}

\end{document}

And there you go. It is a clear, easy and elegant solution to a non-trivial problem and another proof that LaTex is ridiculously powerful. What other typesetting system lets you do conditionals, loops and arrays? Pretty much none. Once again LaTex saves the day.

This entry was posted in Uncategorized. Bookmark the permalink.



6 Responses to LaTex: Automating Repetition

  1. You are a badass Luke…. and I am both ashamed that I have to keep being the guy who has to ask the stupid questions on LaTeX (I believe it was another question of mine which inspired the how to latex series), and happy that I can ask the questions that other LaTeX noobs have, but don’t know who to ask.

    It does have a steep learning curve, but I am getting it.

    Reply  |  Quote
  2. astine Mozilla Firefox Windows says:

    huh… I would have jumped straight to Ruby to make a hundred nearly identical LaTeX files. This is cleaner.

    Reply  |  Quote
  3. @ astine:

    Yup, that’s how I would have done it too. I’d stick a placeholder in the address location and have a script do a string replace on it for each letter.

    Reply  |  Quote
  4. Luke Maciak UNITED STATES Mozilla Firefox Windows Terminalist says:

    @ Travis McCrea:

    Glad I could help. :)

    @ astine:

    I’d like to think this would be easier to manage in the future. It’s a single file, and it generates a single PDF. File generation could get messy.

    @ Chris Wellons:

    It would work too. Although it is a bit of a “if your favorite tool is a hammer, you’ll be doing a lot of inventive nailing” type of approach. I figured that there is no way someone did not try to do this with LaTex before. The language is mature enough to have at least a few extensions and plugins for just about every occasion so there was no reason for me to reach for a hammer just yet. :)

    Reply  |  Quote
  5. Btw Luke, in your reply code or author code within comment.php you have it set to have an inline style which gives: “background-color: #FFFFDC;” to a div.

    I would suggest adding “padding:5px” to that as well. Its been a pet peve of mine :P

    Reply  |  Quote
  6. Paul CANADA Mozilla Firefox Ubuntu Linux says:

    Ten years ago, I was faced with the problem of printing serial numbers on 1000 computer-readable answer forms. This meant printing precisely-positioned black rectangles on every sheet. I thought about it for a moment and realized that the best tool for the job was TeX.

    So I wrote a 10-line TeX document, adjusted the constants by printing a sample sheet and carefully measuring the position of the rectangles, and TeXed the result, making a 1000-page PDF that, when printed, produced exactly what was required.

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *