# How to replace a large block of text by an empty block of the same size?

I know there exists the \phantom command, but does it work on large blocks of text (containing several paragraphs or even several pages)?

What I want is to have some commands, call them \hide and \show, that hide\show the text that it is typeset, leaving empty space where the text should be. To be more clear, when I put the \hide command, everything that appears after it (until a \show command appears) should be replaced with white empty space.

As a temporary solution, I thought coloring text in white, but this does not always works as expected. Maybe there is a more elegant way of doing this.

Edit:

In the meantime, I thought of one possible alternative solution: using the current font, generate a "blank" font that has the same metrics and use this blank font to "hide" the text. Is it possible?

Note: I've created a separate thread for this new question: Generate a “blank” font using the metrics of another font.

-
Why do you try to use "\iffalse" and "\fi"? – wu guiping Apr 18 '12 at 7:50
@wuguiping: \iffalse .. \fi would not generate an empty block as requested in the question. – Martin Scharrer Apr 18 '12 at 8:08
If you care just for the effect, then you could just use \usepackage{xcolor} and \textcolor{background_color}{your text} to make your font have the same color as the background. Of course text could be copied without problems, but if you plan to print the document it would probably be ok. – pmav99 Sep 25 '12 at 15:13

I think you could check out the censor package. It is at least supposed to work by replacing the text with a black box (redacting).

-
I think you mean the censor package. AFAIK, it doesn't work with whole paragraphs as well. – Martin Scharrer Feb 1 '12 at 14:30
@martinscharrer: the release (this week) of a new version of censor might improve things: it will redact anything that can appear as a box. probably not enough for this application, but i couldn't swear to it. – wasteofspace Feb 22 '13 at 16:11

The problem with the \phantom macro is that it places its content into restricted horizontal mode, i.e. in a horizontal box which isn't broken. Therefore it can't include line breaks or paragraphs. Normally you could overcome this issue by placing the content into a minipage environment first, which allows multiple paragraphs. In order to not have to specify the width you can use the similar varwidth environment from the varwidth package instead. However \phantom is unfortunatly not defined as a long macro and therefore you can't have paragraph breaks in it. You would need to box the content yourself first then use \phantom on it or execute the underlying code yourself. The first method is pretty easy using the adjustbox package.

\usepackage{adjustbox}
\usepackage{varwidth}

\newcommand{\Hide}{%
}
% Usage: \Hide{<content, can be multiple paragraphs>}
%    or  \Hide\bgroup <content, ...> \egroup


Your idea with \hide and \show is more complicated. It is possible to write some code which does this, but handling page breaks is difficult.

Some basic code which uses a vertical box instead would be:

\documentclass{article}

\newcommand{\hideit}{%
\begingroup
\par
\setbox0\vbox\bgroup
}
\newcommand{\showit}{%
\egroup
\setbox1\vbox{}%
\ht1=\ht0
\wd1=\wd0
\dp1=\dp0
\box1
\endgroup
}

\begin{document}

This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.

\hideit
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
\showit

This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.

\end{document}


However it does not support page breaks and does not add 100% the same height as the normal text, because of the missing line skip between the \vbox and the surrounding paragraphs. But it is very close. Page break support could be added by e.g. checking the height against \pagetotal and \pagegoal.

-
It still does not work with multiple paragraphs. The erros is {\begin {varwidth}{\linewidth } ! Paragraph ended before \makeph@nt was complete. – digital-Ink Feb 1 '12 at 14:50
@digital-Ink: Ok, I didn't checked if \phantom is "long", i.e. allows paragraph breaks in it. I changed the first part of my answer now. – Martin Scharrer Feb 1 '12 at 15:02
I also have some \label commands inside the part that I want hidden. Using your first solution, they also become hidden, so using \ref to those labels outside the hidden part does not work (as if the labels are missing). – digital-Ink Feb 1 '12 at 17:24
@digital-Ink: \labels only work when they are being typeset. Using both techniques the content is actually discarded and replaced by an empty box of the same dimensions, so they won't work. – Martin Scharrer Feb 1 '12 at 19:35
Should be a package! – Matthew Leingang Feb 2 '12 at 13:18

If the paragraph contains only text, but no other environments or displayed math, the following will count the number of lines and print a blank line for each line in the paragraph; so it will work also across page breaks:

\documentclass{article}
\usepackage{xparse,lipsum}
\ExplSyntaxOn
\cs_new:Npn \vbox_set_end_nopar: { \c_group_end_token }
\NewDocumentCommand{\hideit}{ }
{
\vbox_set:Nw \l_tmpa_box
\cs_set:Npn \par
{
\tex_par:D
\int_gset:Nn \g_tmpa_int { \prevgraf }
\vbox_set_end_nopar:
\prg_replicate:nn { \g_tmpa_int } { \mbox{}\hfill\break }
}
}
\ExplSyntaxOff

\begin{document}
\lipsum*[1]

\hideit
\lipsum*[1]

\lipsum*[1]
\end{document}

-
Unfortunately, there is also a lot of math and other stuff, not only text, that I do not want displayed. – digital-Ink Feb 1 '12 at 17:14
The same idea could work for producing a paragraph made of empty lines as high as the text to be omitted; but the pagination will not in general be preserved, as it depends on the actual text. A different approach might be to dismantle the box item by item, but some items cannot be restored (nor thrown away), unfortunately, so also this approach can't be general. – egreg Feb 1 '12 at 17:51
\vbox{Abc$$cde$$\par\unskip\unpenalty\setbox0\lastbox\unskip\unskip\unpenalty\s‌​etbox0\lastbox\tracingall\showlists} tells me that you can dismantle most "normal" material. You'd have problems with whatsits (e.g., color changes?), and probably figures. One approach might be to hook into the shipout and go through \box255 at that time. The package atbegshi (Heiko, of course) could be useful. – Bruno Le Floch Feb 2 '12 at 5:01
I'm silly. Of course atbegshi would be pointless here. The right solution I believe is to define \hideit{#1} as \vbox\bgroup#1\par\dismantle\egroup, where \dismantle goes through the box one item at a time (be it a box, a penalty, a glue, or a kern) and rebuilds the box afterwards. – Bruno Le Floch Feb 2 '12 at 5:48
@BrunoLeFloch Yes, that's the idea; however whatsits would ruin the business, as they can't be removed. – egreg Feb 2 '12 at 7:56

A slightly different approach from Martin's fine solution, but without the need to use any box measurements.

\documentclass{article}
\usepackage{lipsum}
\long\def\hide#1\show{%
\leavevmode\par
\hspace*{-10000pt}\vbox\bgroup#1\egroup
\par
}
\def\show{}
\begin{document}
Mark A
\hide
\lipsum[1-2]
\show
Mark B
\end{document}


You do not say why you want the text to be hidden, as it can affect the solutions offered.

-
I simply want to be able to easily switch on and off a part from the document that (temporarily) I do not want displayed, but I also want the white space where that part of the document should be. – digital-Ink Feb 1 '12 at 17:19
Unfortunately, your solution does not preserve the space from the initial document, neither on the horizontal, nor the vertical; the white space is very different than that of the hidden text; I want them to be the same. – digital-Ink Feb 1 '12 at 17:39
@digital-Ink It works in my example, what type of text are you inserting? – mathspasha Feb 2 '12 at 9:09
@digital-Ink As long as there are no page breaks, this solution will work, although it simply pushes the text out of the way, to the left. An alternative to \hspace*{-10000pt}\vbox... would be \moveleft-10000pt\vbox... (a plain TeX construct which literally moves the box to the left). – Bruno Le Floch Feb 2 '12 at 14:22

The spacing can be exactly preserved (at least I think this answer does it), with page breaks allowed, and equations. There may be problems with color, and other tools which insert "whatsits" in vertical mode; figures and footnotes are probably not supported either.

Inspired in part by egreg's answer. The idea is to typeset the content that you want to hide inside a vertical box, then go through the box and convert every item in the box to an equivalent transparent item, with the same page-breaking properties.

Namely, there are four main types of objects that can appear in vertical mode (this is a convenient lie!): a skip, a kern, a penalty, or a box. Skips are stretchable (and shrinkable) spaces, they are converted to a skip of the same amount. Kerns are non-stretchable spaces, they are converted to kerns of the same amount. Penalties give TeX incentives to break the page; again, we leave them unchanged. Finally, boxes are what contains material to be typeset. We convert them to vertical boxes with the same exact height+depth, but no contents.

To avoid spurious spaces when stacking \vboxes, I had to set \baselineskip, \lineskip, and \lineskiplimit to zero; there are probably better ways. The integer \l_mypkg_cleanup_int, which is the first (optional) argument of \hideit, takes care of removing skips, kerns, and penalties of size 0, which otherwise make the rest of the code choke. This integer may need to be increased if for some reason the text to hide contains several skips/kerns/penalties of size 0 in a row.

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\box_new:N \l_mypkg_box
\int_new:N \l_mypkg_cleanup_int
\DeclareDocumentCommand{\hideit}{O{1}+m}
{
\tex_setbox:D \l_mypkg_box \tex_vbox:D
{
#2\par
\dim_zero:N \tex_baselineskip:D
\dim_zero:N \tex_lineskip:D
\dim_zero:N \tex_lineskiplimit:D
\int_set:Nn \l_mypkg_cleanup_int {#1}
\mypkg_dismantle_loop:
}
\tex_unvbox:D \l_mypkg_box
}
\cs_new_protected:Npn \mypkg_dismantle_loop:
{
\prg_replicate:nn { \l_mypkg_cleanup_int }
{
\skip_if_eq:nnT { \tex_lastskip:D } { \c_zero_skip } { \tex_unskip:D }
\dim_compare:nT { \tex_lastkern:D = \c_zero_dim } { \tex_unkern:D }
\int_compare:nT { \tex_lastpenalty:D = \c_zero } { \tex_unpenalty:D }
}
\skip_if_eq:nnTF { \tex_lastskip:D } { \c_zero_skip }
{
\dim_compare:nTF { \tex_lastkern:D = \c_zero_dim }
{
\int_compare:nTF { \tex_lastpenalty:D = \c_zero }
{
\box_set_to_last:N \l_mypkg_box
\box_if_empty:NF \l_mypkg_box
{ \mypkg_dismantle_box: }
}
{ \mypkg_dismantle_penalty: }
}
{ \mypkg_dismantle_kern: }
}
{ \mypkg_dismantle_skip: }
}
\cs_new_protected:Npn \mypkg_dismantle_skip:
{ \mypkg_dismantle_aux:nN { \tex_vskip:D \skip_use:N \tex_lastskip:D } \tex_unskip:D }
\cs_new_protected:Npn \mypkg_dismantle_kern:
{ \mypkg_dismantle_aux:nN { \tex_kern:D \dim_use:N \tex_lastkern:D } \tex_unkern:D }
\cs_new_protected:Npn \mypkg_dismantle_penalty:
{ \mypkg_dismantle_aux:nN { \tex_penalty:D \int_use:N \tex_lastpenalty:D } \tex_unpenalty:D }
\cs_new_protected:Npn \mypkg_dismantle_box:
{ \mypkg_dismantle_aux:nN { \tex_vbox:D to \dim_eval:n { \box_ht:N \l_mypkg_box + \box_dp:N \l_mypkg_box } { } } \scan_stop: }
\cs_new_protected:Npn \mypkg_dismantle_aux:nN #1#2
{
\use:x
{
#2
\mypkg_dismantle_loop:
#1 \scan_stop:
}
}
\ExplSyntaxOff
\usepackage{lipsum}
\begin{document}
\lipsum[1-3]
\hideit[2]
{
\lipsum[4-5]
$$x^2+y^2 = z^2$$
\lipsum[6-7]
}
\lipsum[8-10]
\end{document}

-
This code gives me an error: \skip_if_eq:nnT undefined at line 71? – Matthew Leingang Feb 9 '12 at 14:49
@MatthewLeingang: your version of expl3 is probably too old. For old versions of expl3, you can change the line containing \skip_if_eq:nnT to \str_if_eq:xxT { \tex_the:D \tex_lastskip:D } { \tex_the:D \c_zero_skip } { \tex_unskip:D }. – Bruno Le Floch Feb 9 '12 at 18:34

Adding another answer for a new method, which uses LuaLaTeX and the fairly recent chickenize package, which provides the \tabularasa command.

Unfortunately some parts still remain, notably rules and some math formulas. Also footnote markers remain, but this will possibly be taken care of by later versions of the package.

\documentclass{article}
\usepackage{chickenize}

\newcommand{\hideit}{\tabularasa}
\newcommand\showit{\par\untabularasa}

\textheight=.5\textheight

\begin{document}

This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.\footnote{abc} $\frac{1}{2}+a\sqrt{2}$

\hideit
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.\footnote{abc} $\frac{1}{2}+a\sqrt{2}$
\showit

This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.
This is a test paragraph.  This is a test paragraph.\footnote{abc} $\frac{1}{2}+a\sqrt{2}$

\end{document}


The remaining text may be cleared off (but it will be present nonetheless, so this might be a problem) with

\newcommand{\hideit}{\tabularasa\color{white}}
\newcommand\showit{\par\untabularasa\color{black}}


Single words inside a paragraph can be fed to the macro \texttabularasa. Note that \tabularasa and \untabularasa work on complete paragraphs.

-

Here's an alternative approach that avoids having to measure boxes. It requires two runs. On the first run it inserts a marker at the start and end of the part that you want to remove. On the second run when it encounters the first marker then it stops, swallows the stuff you want to remove, and then resumes at the new marker. The removed text is simply thrown away (so any assignments therein are also thrown away).

It's not perfect, there appear to be some small jumps (and for some reason it takes a couple of runs to stabilise the resumption) so it's more of a proof-of-concept that anything else.

It uses the tikzmark library from the TeX-SX Launchpad project, but this is more of a convenience than anything else.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/43069/86}
\usepackage{tikz}
\usetikzlibrary{calc,tikzmark}
\usepackage{lipsum}

\makeatletter

\def\tikzmark@getraw#1#2{%
\edef\tikzmk@x{\strip@sp#1}%
\edef\tikzmk@y{\strip@sp#2}%
}

\def\strip@sp#1sp{#1}%

\newcommand\pgfpassmark[1]{%
\bgroup
\edef\pgfpictureid{pgfid\the\pgf@picture@serial@count}%
\immediate\write\pgfutil@auxout{%
\string\savepicturepage{\pgfpictureid}{\csname save@pg@\csname save@pt@#1\endcsname\endcsname}}%
\immediate\write\pgfutil@auxout{%
\string\savepointas{#1}{\pgfpictureid}}%
\let\pgfqpoint=\tikzmark@getraw
\csname pgf@sys@pdf@mark@pos@\csname save@pt@#1\endcsname\endcsname
\immediate\write\pgfutil@auxout{%
\string\pgfsyspdfmark{\pgfpictureid}{\tikzmk@x}{\tikzmk@y}%
}%
\egroup
}

\makeatother

\newcounter{hidden}
\newif\ifshowtext
%\showtexttrue
\ifshowtext
\newcommand\hideit{\stepcounter{hidden}\pgfmark{hide-\the\value{hidden}}}
\newcommand\showit{\pgfmark{show-\the\value{hidden}}}
\else
\long\def\hideit#1\showit{%
\stepcounter{hidden}\pgfpassmark{hide-\the\value{hidden}}\pgfpassmark{show-\the\value{hidden}}%
\count255=\csname save@pg@\csname save@pt@show-\the\value{hidden}\endcsname\endcsname\relax
\ifnum\count255=0\relax
\tikz[remember picture] \draw (pic cs:hide-\the\value{hidden} -| {pic cs:show-\the\value{hidden}}) -- (pic cs:show-\the\value{hidden});%
\else
\loop\ifnum\count255>0\relax
\newpage
\repeat
\tikz[remember picture] \path (0,0 -| {pic cs:show-\the\value{hidden}}) -- (pic cs:show-\the\value{hidden});%
\fi
}
\fi

\begin{document}

\lipsum[1]

\hideit
\lipsum
\showit

\lipsum[2]
\end{document}


-