Censor text spanning multiple lines

I'd like to censor or hide some text while replacing it with the appropriate amount of white-space. The replacement text cannot be searchable. The text to be hidden usually exists in the LR mode. The censor and invisible packages do not seem to work well with text spanning multiple lines.

One solution, I believe, would be to turn each word into an appropriately sized box, \makebox[\wordwidth]{}, and let TeX (or LaTeX) handle the rest since \makebox is treated like a word.

I am very \sloppy, so the problem is hopefully simplified because you don't need to worry about whether a dash will be placed in the middle of a word. (Although, the soul package is capable of handling such situations.)

-
Welcome to Tex.SX. It may be helpful to know the medium in which you want to hide the text. For example, specifying white text colour when printing to a mono laser printer will achieve the aim for printed output but not for a distributed pdf file; you mentioned soul but not why, say, a black highlight with soul is not adequate. – mas Aug 22 '11 at 14:09
Will your text span multiple paragraphs as well? – Werner Aug 22 '11 at 16:49
It is possible, although, if I could get something to work within a paragraph I'd be happy with that. – Graham Malmgren Aug 22 '11 at 16:54
By the way, there is a very related question: Phantom and line break – diabonas Aug 22 '11 at 20:07

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}


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.

-
 This is a great solution. I'll leave mine simply because it does not rely on any other packages. – Werner Aug 22 '11 at 18:42 @Werner Credits go to the developers of the soul package :-) I agree it's wise to keep your solution, too, as it is much less complicated - this is a great advantage if problems with the soul package should arise, as it's easier to track down errors in straightforward code. (+1) – diabonas Aug 22 '11 at 19:27

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:

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 problem with this solution is that it doesn't preserve the layout when censoring hyphenated words (try applying \censor to "tincidunt" or "suscipit"). This feature, however, is requested in the question, as far as I understand it. – diabonas Aug 22 '11 at 18:10 @diabonas: The OP refers to being \sloppy and therefore not concerned about hyphenation. Moreover, placing something in a box using \makebox[..][.]{...} would void hyphenation anyway. Moreover, the OP should be able to modify the code to use soul that would accommodate hyphenation. I didn't attempt anything with soul. – Werner Aug 22 '11 at 18:14 I do think the OP means hyphenation when referring to "worry about whether a dash will be placed in the middle of a word." So he doesn't want to treat hyphenated words specially. – diabonas Aug 22 '11 at 18:18 I like your answer and you were correct in assuming I wasn't too worried about hyphens. One question though: Any idea why some of the spacing did change slightly, although the entire paragraph (height) would be maintained? – Graham Malmgren Aug 22 '11 at 19:51 @Graham: \sloppy allows for sloppy line-breaking (through hyphenation). However, fundamentally it still allows line-breaking and therefore hyphenation. For now, my solution does not take this into account. Using a \raggedright (instead of \sloppy) alignment would eliminate hyphenation and provide a sufficient solution. The reason for maintaining the entire paragraph (height) is because hyphenation is very sparse - very text-dependent - and therefore not that noticeable. – Werner Aug 22 '11 at 19:57

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

-
 As of 2/19/13, the censor package has been upgraded to V3.00, allowing censoring of "boxed" objects like tables, figures, etc. – Steven B. Segletes Feb 19 at 16:41