Censor text spanning multiple lines

Here's a quick solution using the customization possibilities of the soul package. More information on how this works can be found in the package documentation, p. 22-25.

\documentclass{article}

\usepackage{soul}
\makeatletter
\DeclareRobustCommand*\censor{%
    \SOUL@setup%
    \def\SOUL@everytoken{\phantom{\the\SOUL@token}}%
    \def\SOUL@everyhyphen{%
        \discretionary{%
            \SOUL@setkern\SOUL@hyphkern%
            \phantom{\SOUL@sethyphenchar}%
        }{}{}%
    }%
    \def\SOUL@everyexhyphen##1{%
        \SOUL@setkern\SOUL@hyphkern%
        \hbox{\phantom{##1}}%
        \discretionary{}{}{%
            \SOUL@setkern\SOUL@charkern%
        }%
    }%
    \SOUL@%
}
\makeatother

\begin{document}
One morning, when Gregor Samsa woke from troubled dreams, he found himself
transformed in his bed into a horrible vermin. He lay on his armour-like back,
and if he lifted his head a little he could see his brown belly, slightly domed
and divided by arches into stiff sections. The bedding was hardly able to cover
it and seemed ready to slide off any moment. His many legs, pitifully thin
compared with the size of the rest of him, waved about helplessly as he looked.
``What's happened to me?'' he thought. It wasn't a dream. His room, a proper
human room although a little too small, lay peacefully between its four familiar
walls. A collection of textile samples lay spread out on the table -- Samsa was
a travelling salesman -- and above it there hung a picture that he had recently
cut out of an illustrated magazine and housed in a nice, gilded frame.

One morning, when Gregor Samsa woke from troubled dreams, he found himself
transformed in his bed into a horrible vermin. He lay on his
\censor{armour-like} back, and if he lifted his head a little he could see his
brown belly, slightly domed and divided by arches into stiff sections. The
bedding was hardly able to cover it and seemed ready to slide off any moment.
His many legs, pitifully thin compared with the size of the rest of him, waved
about helplessly as he looked. \censor{``What's happened to me?''} he thought.
It wasn't a dream. His room, a proper human room although a little too small,
lay peacefully between its four familiar walls. A collection of textile samples
lay spread out on the table -- \censor{Samsa was a travelling salesman} -- and
above it there hung a picture that he had recently cut out of an illustrated
magazine and housed in a nice, gilded frame.
\end{document}

output result

This solution allows to censor multiple lines and also treats hyphenated words correctly (see "armour-like"). As the characters are completely replaced by whitespace using \phantom, the censored text isn't written to the resulting PDF at all and therefore can't be extracted.


Understandably you would like to be able to momentarily "escape" into "censor mode" within a paragraph but still keep the formatting of the document. In that sense it is best to provide a command that will take some text as an argument, rather than breaking a paragraph midstream to translate to an environment and cause possible paragraph breaks.

The following was taken and modified from the post A macro that passes each word of its argument to another macro as an argument?. This minimal working example provides the command \censor{<stuff>} that parses <stuff> word-by-word, placing each word in \phantom, thereby preserving the alignment/spacing. Here the command \phantom provides the censor functionality. It would be possible to modify this to accommodate other means of censoring (like changing the color, for example).

\documentclass{article}
\begin{document}

\def\censor#1{\censorloopword#1 \nil}
\def\censorloopword#1 #2\nil{%
  \phantom{#1} % <- Note the space!
  \ifx&#2&% #2 is empty, then & equals &
    \let\next\relax
  \else
    \def\next{\censorloopword#2\nil}% iterate
  \fi
  \next\ignorespaces}

\def\do#1{#1}

\sloppy

\noindent \textbf{Censored paragraph:} \medskip

\mbox{}\censor{Lorem ipsum dolor} sit amet, consectetur adipiscing elit. Suspendisse \censor{massa} lorem, malesuada 
ac imperdiet nec, adipiscing ut lorem. Nunc dignissim nibh erat. Phasellus fermentum lectus 
ut mi viverra a pulvinar turpis interdum. Maecenas mollis laoreet consequat. Etiam malesuada 
ultrices blandit. Praesent sem felis, consectetur eu consectetur id, tempor id quam. \censor{Cras id 
lectus vitae dolor varius} laoreet. Suspendisse nec metus non justo iaculis ultricies quis 
vel enim. In \censor{porttitor} dictum orci sit amet feugiat. Praesent pellentesque odio eu orci 
interdum pulvinar. Suspendisse potenti. Mauris \censor{lacus} lacus, congue tincidunt condimentum 
vitae, elementum quis nibh. Cum sociis natoque penatibus et magnis dis parturient montes, 
nascetur ridiculus mus. \censor{Nulla venenatis iaculis} mauris, vitae semper neque ullamcorper et. 
Integer et sem eu enim egestas pretium. Sed nulla sapien, pretium eget viverra ut, sollicitudin 
tempor urna. In accumsan euismod augue at sagittis. Sed \censor{molestie tincidunt} erat \censor{eu} suscipit. 
Nullam placerat, ipsum a facilisis venenatis, metus est adipiscing augue, at pharetra enim 
dui sit amet metus.

\bigskip

\noindent \textbf{Uncensored paragraph:} \medskip

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse massa lorem, malesuada 
ac imperdiet nec, adipiscing ut lorem. Nunc dignissim nibh erat. Phasellus fermentum lectus 
ut mi viverra a pulvinar turpis interdum. Maecenas mollis laoreet consequat. Etiam malesuada 
ultrices blandit. Praesent sem felis, consectetur eu consectetur id, tempor id quam. Cras id 
lectus vitae dolor varius laoreet. Suspendisse nec metus non justo iaculis ultricies quis 
vel enim. In porttitor dictum orci sit amet feugiat. Praesent pellentesque odio eu orci 
interdum pulvinar. Suspendisse potenti. Mauris lacus lacus, congue tincidunt condimentum 
vitae, elementum quis nibh. Cum sociis natoque penatibus et magnis dis parturient montes, 
nascetur ridiculus mus. Nulla venenatis iaculis mauris, vitae semper neque ullamcorper et. 
Integer et sem eu enim egestas pretium. Sed nulla sapien, pretium eget viverra ut, sollicitudin 
tempor urna. In accumsan euismod augue at sagittis. Sed molestie tincidunt erat eu suscipit. 
Nullam placerat, ipsum a facilisis venenatis, metus est adipiscing augue, at pharetra enim 
dui sit amet metus.

\end{document}

As a comparison, the above document prints both a partially censored paragraph above the uncensored version, to showcase the censoring capability:

Censoring components of a paragraph

A couple of things to note in the code:

  1. There is a space after \phantom{#1} % that acts as the token for parsing the argument to \censor word-by-word. That is, it is assumed words will be separated by spaces.
  2. If you want to censor the start of a paragraph, prepend \censor{<stuff>} with \mbox{} to create a "starting point" for the paragraph, otherwise <stuff> is gobbled.
  3. The argument of \censor cannot take a paragraph break. In that case, split \censor across the paragraph break, using \mbox{} at the start of the next paragraph.
  4. \censor can be nested: \censor{... \censor{...} ...}.
  5. Make careful use of spaces. For example, \censor{<stuff> } <more-stuff> may cause issues due to \ignorespaces.

The LaTeX censor package has been revised (Version 2.1 currently). It can now handle censoring across multiple lines of a document and (with a small inconvenience) across multiple paragraphs. Additionally, its ability to preserve the layout with respect to the uncensored document has been improved