3

Many times, I need to print an exam with a public printer to check its format and layout. However, it would be great to have a switch that replaces all the text with dummy text so that the exam confidentiality couldn't be breached.

For the sake of completeness, it would be perfect if the long text can be replaced by a long dummy text and vice versa for the short question text. In other words, the replacement needs to be done on word basis.

\documentclass{exam}

\begin{document}
\begin{questions}
    \question[7] 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text.
    \begin{parts}
        \part[5] some text to be replaced by a dummy text
        \begin{subparts}
            \subpart[3] to be replaced by a dummy text
            \begin{subsubparts}
                \subsubpart[1] some question to be replaced by a dummy text
            \end{subsubparts}
        \end{subparts}
     \begin{choices}
        \choice a short text to be replaced by a short one.
     \end{choices}
    \end{parts}
\end{questions}
\end{document}
Diaa
  • 9,599
  • See https://tex.stackexchange.com/questions/470479/in-latex-is-there-good-way-to-optionally-redact-certain-sections-of-a-document The duplicate link only handles the conditional part. The rest comes from the comments. – John Kormylo Jan 07 '20 at 18:49
  • @JohnKormylo Thanks but I don't want to censor or blackout any text. I just need a switch to turn every word into a dummy one. – Diaa Jan 07 '20 at 19:03
  • I figured redacting would be easier (already solved problem). – John Kormylo Jan 08 '20 at 05:00

1 Answers1

4

A brute-force (and quite slow) solution can be adapted from here: How to do multiple string replacements?

Basically, I'm defining an obfuscate environment, so every alphabetical character is replaced by a lowercase X

\documentclass{exam}
\usepackage{xstring}
\usepackage{environ}
\def\obfuscatetext{0}
\newcommand{\xeverywhere}[2]{%
    \expandafter\StrSubstitute\expandafter{\BODY}{#1}{#2}[\BODY]%
}
\NewEnviron{obfuscate}{{%
\ifnum\obfuscatetext=1 
    \expandarg
    \StrSubstitute{\BODY}{a}{x}[\BODY]%
    \xeverywhere{b}{x}%
    \xeverywhere{c}{x}%
    \xeverywhere{d}{x}%
    \xeverywhere{e}{x}%
    \xeverywhere{f}{x}%
    \xeverywhere{g}{x}%
    \xeverywhere{h}{x}%
    \xeverywhere{i}{x}%
    \xeverywhere{j}{x}%
    \xeverywhere{k}{x}%
    \xeverywhere{l}{x}%
    \xeverywhere{m}{x}%
    \xeverywhere{n}{x}%
    \xeverywhere{o}{x}%
    \xeverywhere{p}{x}%
    \xeverywhere{q}{x}%
    \xeverywhere{r}{x}%
    \xeverywhere{s}{x}%
    \xeverywhere{t}{x}%
    \xeverywhere{u}{x}%
    \xeverywhere{v}{x}%
    \xeverywhere{w}{x}%
    \xeverywhere{y}{x}%
    \xeverywhere{z}{x}%
    \xeverywhere{A}{x}%
    \xeverywhere{B}{x}%
    \xeverywhere{C}{x}%
    \xeverywhere{D}{x}%
    \xeverywhere{E}{x}%
    \xeverywhere{F}{x}%
    \xeverywhere{G}{x}%
    \xeverywhere{H}{x}%
    \xeverywhere{I}{x}%
    \xeverywhere{J}{x}%
    \xeverywhere{K}{x}%
    \xeverywhere{L}{x}%
    \xeverywhere{M}{x}%
    \xeverywhere{N}{x}%
    \xeverywhere{O}{x}%
    \xeverywhere{P}{x}%
    \xeverywhere{Q}{x}%
    \xeverywhere{R}{x}%
    \xeverywhere{S}{x}%
    \xeverywhere{T}{x}%
    \xeverywhere{U}{x}%
    \xeverywhere{V}{x}%
    \xeverywhere{W}{x}%
    \xeverywhere{Y}{x}%
    \xeverywhere{X}{x}%
    \xeverywhere{Z}{x}%
    \BODY
\else 
    \BODY
\fi 
}}
\let\oldtextbf\textbf
\let\oldtextit\textit
\let\oldtexttt\texttt
\renewcommand{\textbf}[1]{\oldtextbf{\begin{obfuscate}#1\end{obfuscate}}}
\renewcommand{\textit}[1]{\oldtextit{\begin{obfuscate}#1\end{obfuscate}}}
\renewcommand{\texttt}[1]{\oldtexttt{\begin{obfuscate}#1\end{obfuscate}}}
\newcommand{\ObfuscateON}{%
\renewcommand{\obfuscatetext}{1}
}
\newcommand{\ObfuscateOFF}{%
    \renewcommand{\obfuscatetext}{0}
}
\ObfuscateON
\begin{document}
%If I want normal text, I just delete the next line:
\ObfuscateON
\begin{obfuscate}
\begin{questions}
    \question[7] 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text.
    \begin{parts}
        \part[5] some text to be replaced by a dummy text
        \begin{subparts}
            \subpart[3] to be replaced by a dummy text
            \begin{subsubparts}
                \subsubpart[1] some question to be replaced by a dummy text
            \end{subsubparts}
        \end{subparts}
     \begin{choices}
        \choice a short text to be replaced by a short one.
     \end{choices}
    \end{parts}
\end{questions}
\end{obfuscate}
\end{document}

enter image description here

Numbers and punctuation signs can be added ad libitum in the definition of obfuscate

EDIT: I added the \ObfuscateON command. obfuscate will do nothing by default, so it will only work if \ObfuscateON is used. I also patched the definitions of \textbf, \textit, and \texttt so obfuscate works.

EDIT AGAIN: As my first solution has so many bugs, I've come up with a nice solution using lualatex and chickenize which avoid clashes with other packages. As for graphics, using draft option suffices.

%!TEX program = lualatex
\documentclass{exam}
\usepackage{luacode}
\usepackage[draft]{graphicx}
\usepackage{chickenize}
\begin{luacode*}
    chickenizefraction = 100000
    chickenstring[1] = "ayyyy"
    chickenstring[2] = "lol"
    chickenstring[3] = "lmao"
    chickenstring[4] = "haha"
\end{luacode*}
\begin{document}
%Delete chickenize or use \unchickenize to get normal text
\chickenize
\begin{questions}
    \question[7] 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text. 
    some  very long question body to be replaced by a very long dummy text.
    \begin{parts}
        \part[5] some text to be replaced by a dummy text
        \begin{subparts}
            \subpart[3] to be replaced by a dummy text
            \begin{subsubparts}
                \subsubpart[1] some question to be replaced by a dummy text
            \end{subsubparts}
        \end{subparts}
     \begin{choices}
        \choice a short text to be replaced by a short one.
     \end{choices}
    \end{parts}
\end{questions}
\end{document}

A really better solution

  • I am away from PC to experiment but is it possible to make the replacement conditionally done by a command on my demand? – Diaa Jan 07 '20 at 21:04
  • 1
    @Diaa I've added the switching command. I hope it will be helpful. –  Jan 07 '20 at 22:02
  • 1
    Many thanks for this beautiful answer. – Diaa Jan 07 '20 at 22:10
  • I just found one bug; it doesn't detect uppercase letters and words inside \textbf for example. – Diaa Jan 07 '20 at 22:27
  • 1
    @Diaa Please, see the code again. I've corrected this issue. –  Jan 07 '20 at 22:55
  • 1
    I have just moved away from PC after asking a new question about this issue with more complex example of table with figure to be replaced by a dummy one. I would be grateful if you could check my newly asked question and help me fix the error. – Diaa Jan 07 '20 at 23:01
  • Thanks again for improving the answer. However, I got this error for your 2nd edit: File 'chickenize.tex' not found. \input{chickenize}. – Diaa Jan 08 '20 at 06:23
  • Are you using MiKTeX? As far as I know, TeXLive2019 compiles without any problems. If you can install it from your distribution, try this first. Otherwise, chickenize is here: https://ctan.org/pkg/chickenize so you put the files and your document in the same folder. You can also compile via Overleaf, in case neither of the previous options work. –  Jan 08 '20 at 06:32
  • This document gives the following error: Package keyval Error: align undefined. ...s[width=\linewidth,align=t]{example-image-a}. My main document has many figures, so it is not an easy job to comment them out every time. – Diaa Jan 08 '20 at 06:47