8

What is the best way to stack long passages of (fixed-wdith) text on top of each other? I am writing exercises and solutions for a cryptography class and would like to be able to have plaintext above the ciphertext for many lines. For example:

Question version:

eiydimvexzzwkmf

ntfukuxzzfcjkfy

itizkcjwifkl

Solution version:

jackandjillwent
eiydimvexzzwkmf
upthehilltofetc
ntfukuxzzfcjkfy
apailofwater
itixzcjwifkl

So far I've done this manually one line at a time, but I'd like not to worry about each line individually.

  • by "on top of" do you mean "above and below" or "physically occupying the same location, with one obscuring the other"? (either should be possible, provided the input is arranged suitably.) – barbara beeton Jun 29 '13 at 14:06
  • Is fetcapale instead of fetchapail a typo, or meant to make decoding harder? – Ethan Bolker Jun 29 '13 at 16:31
6

The following might be a start. It sources code from Automatic line breaking of long lines of text? (avoiding the seqsplit package) and Determine width of verbatim characters (for determining the width of the block to store the plain/cypher text) in typewriter (monospaced) font:

enter image description here

\documentclass{article}
\usepackage{setspace,xcolor}% http://ctan.org/pkg/{setspace,xcolor}
\makeatletter
% \plaincyphertextweave[<num chars>]{<plain text>}{<cypher text>}
\newcommand{\plaincyphertextweave}[3][10]{%
  \settowidth{\dimen0}{\ttfamily A}%
  \settoheight{\dimen1}{\ttfamily\strut}%
  \setlength{\dimen0}{\dimexpr#1\dimen0}%
  \leavevmode\rlap{\parbox[t]{\the\dimen0}{\setstretch{2}\scan{#2}\ttfamily\strut\\[\dimexpr-1.7\baselineskip+\dimen1]\@tempa\strut}}% Plain text
  \parbox[t]{\the\dimen0}{\setstretch{2}\scan{#3}\ttfamily\strut\\[\dimexpr-1.2\baselineskip+\dimen1]\color{black!50}\@tempa\strut}% Cypher text
}

% \stacktext[<num chars>]{<text>}
\newcommand{\stacktext}[2][10]{%
  \settowidth{\dimen0}{\ttfamily A}%
  \setlength{\dimen0}{\dimexpr#1\dimen0}%
  \parbox[t]{\the\dimen0}{\scan{#2}\ttfamily\strut\@tempa\strut}%
}
%\def\scanfunction#1{#1}
\def\scan@letters#1#2{%
  \g@addto@macro{\@tempa}{#1\hskip 0pt}%
  \ifx#2\@empty\else 
    \expandafter\scan@letters
  \fi
  #2}
\def\scan#1{\let\@tempa\@empty\scan@letters #1\@empty}
\makeatother
\begin{document}

Default width (10 characters): \par
\stacktext{jackandjillwentupthehilltofetchapailofwater}

Forced width (15 characters): \par
\stacktext[15]{jackandjillwentupthehilltofetchapailofwater}

Plain/cypher text weave (20 characters): \par
\plaincyphertextweave[20]{jackandjillwentupthehilltofetchapailofwater}{retawfoliapahctefotllihehtputnewllijdnakcaj}

Some regular, readable text.
\end{document}

The above example provides \stacktext[<num chars>]{<text>} which stacks <text> at a width of <num chars>. \plaincyphertextweave[<num chars>]{<plain text>}{<cypher text>} has a similar interface, but with an additional (<cypher text>) argument to be weaved inbetween <plain text>. The weaving is obtained by an overlay of two \parboxes.

setspace helps stretch out the text to weave the plain/cypher text combination. Some vertical adjustment is required, since the \baselineskip is latered.

The use of xcolor provides the means to highlight the different plain/cypher text components. It's meant just for illustration purposes.

Caveat: The usage of \parboxes fixes the positioning/anchor at the [t]op. I'm not sure about your use case, so this may not matter. However, if [b]ottom-alignment is required, some changes are required.

6

The following example uses package seqsplit. For the question the text is set with double \baselineskip,

For the solution each texts are set in \parbox commands with double \baselineskip. Then the boxes are set at top of each other with the cypher text box shifted by one \baselineskip:

\documentclass{article}
\usepackage{seqsplit}
\newcommand*{\singlesplit}[2][\linewidth]{%
  \par\noindent
  \begingroup
    \parbox[t]{#1}{%
      \setlength{\baselineskip}{2\baselineskip}%
      \seqsplit{#2}%
    }%
    \par
  \endgroup
}
\newcommand*{\doublesplit}[3][\linewidth]{%
  \par\noindent
  \begingroup
    \ttfamily
    \parbox[t]{#1}{%
      \ttfamily
      \noindent
      \raisebox{0pt}[\height][0pt]{%
        \parbox[t]{#1}{%
          \setlength{\baselineskip}{2\baselineskip}%
          \seqsplit{#2}%
        }%
      }\\%
      \parbox[t]{#1}{%
        \setlength{\baselineskip}{2\baselineskip}%
        \seqsplit{#3}%
      }%
    }%  
    \par
  \endgroup
}


\begin{document}

\subsection*{Question version:}
\singlesplit[8em]{%
  eiydimvexzzwkmf%
  ntfukuxzzfcjkfy%
  itizkcjwifkl%
}

\subsection*{Solution version:}
\doublesplit[8em]{%Result
  jackandjillwent%
  upthehilltofetc%
  apailofwater%
}{
  eiydimvexzzwkmf%
  ntfukuxzzfcjkfy%
  itizkcjwifkl%
}
\end{document}

Result

Remarks:

  • \raisebox{0pt}[\height][0pt]{<stuff>} has the effect that the depth of the box containing stuff is zero. \parbox[t] sets the reference point to the first line. Thus TeX sees the plain text box as box with the dimensions of the first line. In the next line the cypher text box follows.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.