10

I simply need to truncate a text string, which is just a sequence of characters without whitespace, therefore the linebreak won't work. I just need to decide the length of the string in centimeter, the rest should be cut.

I found the package trimclip which could do it, but I need a way to do it without the usage of this package (I can still use existing, common packages)

I hope there is another possibility. I found a very nice way to do it if you want to cut the string from the right side. But I need it from the other side.

I will give a short example how my document should look like:

\documentclass{article}
\newcommand\magicCommand[1]{
      ...
}
\begin{document}

\begin{table}[htb]
\begin{center}
\begin{tabular}{l}

\begin{tabular}{|ll|}
\hline

\parbox{50mm}{ \magicCommand{3cm}{veryLongStringWhichIsGoingToLookUglyInMyDocument}} & \parbox{40mm}{ abc }\\

\hline
\end{tabular}

\end{tabular}
\end{center}
\end{table}

\end{document}

The text for the example above should look in the document like:

veryLongStri

\EDIT

Sorry for this long edit, but I am pretty confused. The truncate seems to be buggy somehow (dependent from the string) and as you can see I made some other tests. There are some solutions which seem to work properly. I don't know what problem I had before because some versions only worked outside the tabular environments.

test.tex

\documentclass[10pt]{article}
\usepackage{a4,graphicx}
\usepackage[breakwords]{truncate}

\setlength{\oddsidemargin}{0cm}
\setlength{\evensidemargin}{0cm}
\setlength{\topmargin}{-2.0cm}
\setlength{\textwidth}{16cm}
\setlength{\textheight}{28.65cm}
\setlength{\headsep}{1.0cm}
\setlength{\parindent}{1.0cm}
\newcommand{\singlespace}{\renewcommand{\baselinestretch}{1.0}\small\normalsize}\newcommand{\doublespace}{\renewcommand{\baselinestretch}{1.5}\small\normalsize}
\renewcommand{\floatpagefraction}{0.95}
\renewcommand{\textfraction}{0.05}
\renewcommand{\topfraction}{0.95}
\renewcommand{\bottomfraction}{0.95}

%===new===

\newlength{\stringlen}
\newbox\stringbox
\newcommand{\clipstring}[2][6cm]{%
  \setlength\stringlen{#1}%
  \sbox\stringbox{}%
  \doclipstring#2\doclipstring
}

\makeatletter
\newcommand{\doclipstring}[1]{%
  \ifx#1\doclipstring
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\unhbox\stringbox}%
  {\check@cliplength{#1}}%
}
\def\check@cliplength#1{%
  \sbox\stringbox{\unhcopy\stringbox #1}
  \ifdim\wd\stringbox>\stringlen
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\unhbox\stringbox\removetrailing}%
  {\doclipstring}%
}
\def\removetrailing#1\doclipstring{}
\makeatother

%=========

\usepackage{xcolor}
\newcommand\tleft[3][white]{%
  \setbox0=\hbox{\x}%
  \makebox[#2][l]{%
    \ooalign{\mbox{#3}\cr\kern#2\textcolor{#1}{%
      \rule[-\dp0]{\wd0}{\dimexpr\dp0+\ht0}}}}%
}

%=========

\makeatletter
\newcommand\jw[2][2cm]{%
  \leavevmode
  \begingroup
    \setbox0=\hbox{#2}%
    \setbox0=\hbox{%
      \pdfsave
      \pdfliteral{%
        0 \dim@in@bp{-\dp0 } \dim@in@bp{#1} \dim@in@bp{\ht0 + \dp0 }
        re W n}%
        \rlap{\box0 }%
      \pdfrestore
      \hskip#1 %
    }%
    \box0 %
  \endgroup
}
\newcommand\dim@in@bp[1]{%
  \strip@pt\dimexpr(#1) * 800/803\relax
}
\makeatother

%=========


\begin{document}

\pagestyle{empty}
\begin{table}[htb]
\begin{center}
\begin{tabular}{l}
\begin{tabular}{|ll|}
\hline
 \parbox{60mm}{ thoseAreTheVeryLongStringsWeWantToCutOtherwiseTheTableLooksLikeCrap\_bad }& \parbox{80mm}{ 0.031 }\\

 \parbox{60mm}{ \truncate{6cm}{qwfioqoiwefjiuwgwejfmqefiuhSiqwdMwqkdwqmkMqdwmDWmdwklqwdmlDMlkqwlkdMDLWQd} }& \parbox{80mm}{ 2.047 }\\
 \parbox{60mm}{ \truncate{6cm}{qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\_qqqq} }& \parbox{80mm}{ 2.047 }\\
 \parbox{60mm}{ \truncate{6cm}{aaaaaaaa\_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\_qqqq} }& \parbox{80mm}{ 2.047 }\\
 \parbox{60mm}{ \truncate{6cm}{truncate\_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\_qqqq} }& \parbox{80mm}{ 2.047 }\\
 \parbox{60mm}{ \truncate{6cm}{thoseAreTheVeryLongStringsWeWantToCutOtherwiseTheTableLooksLikeCrap\_good} }& \parbox{80mm}{ 1.023 }\\

 \parbox{60mm}{ \clipstring{clipstring\_thoseAreTheVeryLongStringsWeWantToCutOtherwiseTheTableLooksLikeCrap} }& \parbox{80mm}{ 1.023 }\\

 \parbox{60mm}{ \tleft{6cm}{tleft\_thoseAreTheVeryLongStringsWeWantToCutOtherwiseTheTableLooksLikeCrap} }& \parbox{80mm}{ 1.023 }\\

 \parbox{60mm}{ \jw[6cm]{jw\_thoseAreTheVeryLongStringsWeWantToCutOtherwiseTheTableLooksLikeCrap} }& \parbox{80mm}{ 1.023 }\\
 \parbox{60mm}{ \jw[6cm]{jw\_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\_qqqq} }& \parbox{80mm}{ 1.023 }\\

\hline
\end{tabular}
\end{tabular}
\end{center}
\end{table}

\end{document}

testoutput

enter image description here

pdflatex.log

This is pdfTeXk, Version 3.141592-1.40.3 (Web2C 7.5.6)
 %&-line parsing enabled.
entering extended mode
(./test.tex
LaTeX2e <2005/12/01>
Babel <v3.8h> and hyphenation patterns for english, usenglishmax, dumylang, noh
yphenation, arabic, basque, bulgarian, coptic, welsh, czech, slovak, german, ng
erman, danish, esperanto, spanish, catalan, galician, estonian, farsi, finnish,
 french, greek, monogreek, ancientgreek, croatian, hungarian, interlingua, ibyc
us, indonesian, icelandic, italian, latin, mongolian, dutch, norsk, polish, por
tuguese, pinyin, romanian, russian, slovenian, uppersorbian, serbian, swedish, 
turkish, ukenglish, ukrainian, loaded.
(/usr/share/texmf/tex/latex/base/article.cls
Document Class: article 2005/09/16 v1.4f Standard LaTeX document class
(/usr/share/texmf/tex/latex/base/size10.clo))
(/usr/share/texmf/tex/latex/ntgclass/a4.sty)
(/usr/share/texmf/tex/latex/graphics/graphicx.sty
(/usr/share/texmf/tex/latex/graphics/keyval.sty)
(/usr/share/texmf/tex/latex/graphics/graphics.sty
(/usr/share/texmf/tex/latex/graphics/trig.sty)
(/usr/share/texmf/tex/latex/config/graphics.cfg)
(/usr/share/texmf/tex/latex/pdftex-def/pdftex.def)))
(/usr/share/texmf/tex/latex/ltxmisc/truncate.sty)
(/usr/share/texmf/tex/latex/xcolor/xcolor.sty
(/usr/share/texmf/tex/latex/config/color.cfg)) (./test.aux)
Overfull \hbox (194.49529pt too wide) in paragraph at lines 96--96
[]\OT1/cmr/m/n/10 thoseAreTheVeryLongStringsWeWantToCutOtherwiseTheTableLooksLi
keCrap[]bad 

Overfull \hbox (207.60631pt too wide) detected at line 99
\OT1/cmr/m/n/10 qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqq[]qqqq 

Overfull \hbox (251.20644pt too wide) detected at line 100
\OT1/cmr/m/n/10 aaaaaaaa[]qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqq[]qqqq 

Overfull \hbox (3.02272pt too wide) in paragraph at lines 104--104
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][
]\OT1/cmr/m/n/10 c[]l[]i[]p[]s[]t[]r[]i[]n[]g[][][]t[]h[]o[]s[]e[]A[]r[]e[]T[]h
[]e[]V[]e[]r[]y[]L[]o[]n[]g[]S[]t[]r[]i[]n[]g[]s[] 
! Undefined control sequence.
\\tleft [#1]#2#3->\setbox 0=\hbox {\x 
                                      }\makebox [#2][l]{\ooalign {\mbox {#3}...
l.106 ...antToCutOtherwiseTheTableLooksLikeCrap} }
                                                  & \parbox{80mm}{ 1.023 }\\
? [1{/usr/share/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./test.aux) )</usr/sh
are/texmf/fonts/type1/bluesky/cm/cmr10.pfb>
Output written on test.pdf (1 page, 12123 bytes).
Transcript written on test.log.
  • With “length” do you refer to a geometric length or to the number of characters? – egreg Sep 26 '14 at 13:08
  • Geometric length, e.g. 3cm of the width of the document. – EverythingRightPlace Sep 26 '14 at 13:09
  • Please help us to help you and add a minimal working example (MWE) that illustrates your problem. It will be much easier for us to reproduce your situation and find out what the issue is when we see compilable code, starting with \documentclass{...} and ending with \end{document}. –  Sep 26 '14 at 13:20
  • @ChristianHupfer Added an example though it's hard to give code because I don't know how the code has to look like. – EverythingRightPlace Sep 26 '14 at 13:27
  • @EverythingRightPlace: The MWE is meant to provide the minimum information on your problem, what you have tried so far etc., such that other users do not have to make wild guesses and start typing a lot of code which is basically already present. I know that it's sometimes difficult to provide a document at all, of course –  Sep 26 '14 at 13:30
  • @ChristianHupfer I think I can just describe the problem and I hope you guys understand me now. It is just the exact same problem which is solved here but I need to cut the other side of the string. – EverythingRightPlace Sep 26 '14 at 13:31
  • What I tried so far is to Google a lot and try some of the ways I found. I gave links in the question. – EverythingRightPlace Sep 26 '14 at 13:32
  • I already gave the link to the other question when I wrote my own question. I made this to describe what my problem is. It is to cut the right side of the text, not the left side. So I don't think it is a duplicate. Right now I am testing your answers. – EverythingRightPlace Sep 26 '14 at 14:33
  • @closers: look at the requested output here and in the “duplicate” question. I have the impression they are different; better, the other question asks a really different thing. – egreg Sep 26 '14 at 14:56
  • @egreg I guess nobody was reading the links I provided. I am still testing, in general both of your answers work but for a little more complex documents I am getting weird problems (I am using the code you provided in a table and tabular environment to prevent the string from going over the edge of the columns). – EverythingRightPlace Sep 26 '14 at 15:10
  • @EverythingRightPlace Could you elaborate on why you can't use trimclip: the restrictions in your use case are presumably important. – Joseph Wright Sep 26 '14 at 15:20
  • @JosephWright Reason is that I am simply not allowed to change anything on the system. I could get an admin to install the trimclip package but I thought there has to be an easier solution. Especially because I don't need all the features of trimclip. – EverythingRightPlace Sep 26 '14 at 15:24
  • I voted for closing since I think this is a duplicate. I thought that solution would work from the other side (…), so the real problem is that you didn't understand the answer. I thought you should ask for a more precise question about what you don't exactly understand, and may be, in a comment there, ask them to add the macros to do it from left to right in the already given answers. But I might have it wrong… – Manuel Sep 26 '14 at 15:30
  • @Manuel I really don't get it. What is unclear in I found a very nice way to do it if you want to cut the string from the right side. But I need it from the other side.? And yes, of course I am asking to get a macro because I don't want to use the package which is able to produce the desired output. – EverythingRightPlace Sep 26 '14 at 15:36
  • @Manuel Truncating on the left and right on a char by char basis are quite different for a start in TeX: removing chars from the left is easier. On the other had, box-based clipping is much easier on the right than on the left, and again differences in approach are required. Moreover, the requirements here seem to be to avoid any additional/non-standard packages, which isn't a limitation in the other question. – Joseph Wright Sep 26 '14 at 15:44
  • @EverythingRightPlace: if it's simply a matter of not having permissions to install packages in the system-wide TeX installation, you can install packages in your own home directory, generally in ~/texmf. – Nick Matteo Sep 27 '14 at 00:22
  • @Kundor Thx but this isn't working because others are going to use the code too. – EverythingRightPlace Sep 27 '14 at 04:05
  • @EverythingRightPlace: You can also just put the files for the trimclip package in the folder with your TeX files. You can share those files along with the rest of your documents with any collaborators. – Nick Matteo Sep 27 '14 at 18:18

4 Answers4

10

Use the truncate package

\documentclass{article}
\usepackage[breakwords]{truncate}
\begin{document}
\truncate{3cm}{This text has been~truncated}
\end{document}

The package uses a clever stategy based on hyphenation. But a word of warning, if you just insert long nonsense letter sequences it may have a problem finding a breakpoint. Use sensible text and works very well. Do read the docs. Use texdoc truncate from the command line, is the quickest way.

yannisl
  • 117,160
7

When doing most box manipulations, you can refer to \width that contains the box's natural width.

\documentclass{article}
\usepackage{trimclip}

\newcommand\clipstring[2][3cm]{%
  \clipbox{0pt 0pt {\dimexpr\width-#1\relax} 0pt}{#2}%
}

\begin{document}

\clipstring{veryLongStringWhichIsGoingToLookUglyInMyDocument} is
not too long any more

\makebox[3cm]{\hrulefill} is not too long any more

\end{document}

I added an optional argument to \clipstring, so you can adjust the length at run time with, say, \clipstring[2cm]{...}.

enter image description here

You may want a macro that clips a string in typewriter type, specifying the number of characters to keep:

\documentclass{article}
\usepackage{trimclip}

\newcommand\clipstring[2][3cm]{%
  \clipbox{0pt 0pt {\dimexpr\width-#1\relax} 0pt}{#2}%
}
\newcommand\clipttstring[2][10]{%
  \texttt{\clipbox{0pt 0pt {\dimexpr\width-(#1em)/2\relax} 0pt}{#2}}%
}

\begin{document}

\clipstring{veryLongStringWhichIsGoingToLookUglyInMyDocument} is
not too long any more

\makebox[3cm]{\hrulefill} is not too long any more % check

\clipttstring{veryLongStringWhichIsGoingToLookUglyInMyDocument} is
not too long any more

\texttt{0123456789} is not too long any more % check

\end{document}

The default is 10, use \clipttstring[6]{...} to keep just six characters.

enter image description here


Here is, instead, a macro that will stop print characters when the fixed length is exceeded.

\documentclass{article}

\newlength{\stringlen}
\newbox\stringbox
\newcommand{\clipstring}[2][3cm]{%
  \setlength\stringlen{#1}%
  \sbox\stringbox{}%
  \doclipstring#2\doclipstring
}

\makeatletter
\newcommand{\doclipstring}[1]{%
  \ifx#1\doclipstring
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\unhbox\stringbox}%
  {\check@cliplength{#1}}%
}
\def\check@cliplength#1{%
  \sbox\stringbox{\unhcopy\stringbox #1}
  \ifdim\wd\stringbox>\stringlen
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\unhbox\stringbox\removetrailing}%
  {\doclipstring}%
}
\def\removetrailing#1\doclipstring{}
\makeatother

\begin{document}

\clipstring{veryLongStringWhichIsGoingToLookUglyInMyDocument} is
not too long any more

\makebox[3cm]{\hrulefill} is not too long any more % check

\clipstring{shrt} is short

\end{document}

enter image description here

Limitations: the argument must be a string of simple ASCII characters; no spaces, though, and no accented letters.


A similar solution, but counting characters to keep (ten by default).

\documentclass{article}
\makeatletter
\newcommand\stringclip[2][10]{%
  \@tempcnta=#1\relax
  \@tempcntb=\z@
  \toks@={}%
  \do@stringclip#2\do@stringclip
}
\def\do@stringclip#1{%
  \ifx#1\do@stringclip
    \the\toks@\expandafter\@gobble
  \else
    \advance\@tempcntb\@ne
  \expandafter\@firstofone
  \fi
  {\check@one@more{#1}}%
}
\def\check@one@more#1{%
  \ifnum\@tempcntb=\@tempcnta
    \the\toks@ #1%
    \expandafter\@firstoftwo
  \else
    \toks@=\expandafter{\the\toks@ #1}%
    \expandafter\@secondoftwo
  \fi
  {\gobble@toend}%
  {\do@stringclip}%
}
\def\gobble@toend#1\do@stringclip{}
\makeatother

\begin{document}

\stringclip{01234567890123456789}

\stringclip[5]{01234567890123456789}

\stringclip{012345}

\end{document}

enter image description here

egreg
  • 1,121,712
  • Sorry if I described my issue badly. I wish to have a solution without the usage of the package trimclip. I would like to have a solution like the one I linked to (where the string is truncated from the other side). – EverythingRightPlace Sep 26 '14 at 13:20
  • @EverythingRightPlace If you want exactly 3cm, you can't do it without trimclip or equivalent method. TeX never prints “half of a character”. – egreg Sep 26 '14 at 13:22
  • It's not necessary that it is exactly 3cm. The last letter can be removed at all. I just need a neat method that my string isn't going over all boarders (edges of tabular and even the edge of the document). – EverythingRightPlace Sep 26 '14 at 13:28
  • @EverythingRightPlace I added a different technique; if your strings are in typewriter type, you could simply count characters. – egreg Sep 26 '14 at 13:41
  • @egreg "TeX never prints half a character" True, but I think you can trick it to... TikZ clippings come to mind, but I haven't the resources to investigate this here at work (I'm on lunch). – Sean Allred Sep 26 '14 at 16:50
  • @SeanAllred That would use the same mechanism as \clipbox; of course the OP might have TikZ available, but I can we know? – egreg Sep 26 '14 at 17:09
6

A solution using driver-level box clipping accessed via expl3 (interface as egreg's version):

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand \clipstring { O { 2cm } m }
  {
    \erp_clip:nn {#2} {#1}
  }
\box_new:N \l__erp_box
\cs_new_protected:Npn \erp_clip:nn #1#2
  {
    \leavevmode
    \hbox_set:Nn \l__erp_box {#1}
    \box_set_wd:Nn \l__erp_box {#2}
    \box_clip:N \l__erp_box
    \box_use:N \l__erp_box
  }
\ExplSyntaxOff

\begin{document}

\clipstring[3cm]{veryLongStringWhichIsGoingToLookUglyInMyDocument} is
not too long any more

\makebox[3cm]{\hrulefill} is not too long any more % check

\end{document}

If absolutely no packages are allowed, we can do the same thing by recoding the low-level clipping 'by hand'. This is tied to one driver, but that may be acceptable. For example, using pdfTeX or LuaTeX for direct PDF production, the above 'written out' is

\documentclass{article}
\makeatletter
\newcommand\clipstring[2][2cm]{%
  \leavevmode
  \begingroup
    \setbox0=\hbox{#2}%
    \setbox0=\hbox{%
      \pdfsave
      \pdfliteral{%
        0 \dim@in@bp{-\dp0 } \dim@in@bp{#1} \dim@in@bp{\ht0 + \dp0 }
        re W n}%
        \rlap{\box0 }%
      \pdfrestore
      \hskip#1 %
    }%
    \box0 %
  \endgroup
}
\newcommand\dim@in@bp[1]{%
  \strip@pt\dimexpr(#1) * 800/803\relax
}
\makeatother

\begin{document}
\clipstring[2.95cm]{veryLongStringWhichIsGoingToLookUglyInMyDocument} is
not too long any more

\makebox[2.95cm]{\hrulefill} is not too long any more % check

\end{document}

(I've made a few minor changes as I can hardcode some stuff in this case that I can't when writing the expl3 driver code!)

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
  • Of course this does use the same underlying idea as trimclip, but it doesn't use the package :-) – Joseph Wright Sep 26 '14 at 15:19
  • If it's really needed I can write out the driver-dependent code for dvips/dvipdfm(x)/XeTeX with some conditionals: won't be pretty but is all doable. – Joseph Wright Sep 26 '14 at 15:48
  • Unfortunately my system is also without the exp13.sty which I try to avoid then. The low-level version generally works. My question wasn't complete, because I want to use the command in a table (using tabular and parbox) which isn't working. Sorry for the unclear question, didn't think this is a problem here. – EverythingRightPlace Sep 26 '14 at 15:54
  • @EverythingRightPlace I have no issue if I replace your \magicCommand in the edited question by either definition here of \clipstring and make the appropriate adjustment of the interface. – Joseph Wright Sep 26 '14 at 16:07
  • @JosephWright Please check the edit. Though I don't know why I had problems with your code beforehand. – EverythingRightPlace Sep 26 '14 at 18:14
5

This uses xcolor instead of trimclip. As egreg correctly points out, my original answer will not work on a colored background. So I have EDITED it to add an optional argument, where the background color can be specified (default white).

EDITED to replace local variable \x inside the \tleft definition with (oops!) #3.

\documentclass{article}
\usepackage{xcolor}
\newcommand\tleft[3][white]{%
  \setbox0=\hbox{#3}%
  \makebox[#2][l]{%
    \ooalign{\mbox{#3}\cr\kern#2\textcolor{#1}{%
      \rule[-\dp0]{\wd0}{\dimexpr\dp0+\ht0}}}}%
}
\begin{document}
\def\x{This is my very long string}
\x

\rule{1.4cm}{2pt}

\tleft{1.4cm}{\x}NEXT
\end{document}

enter image description here

  • This won't work over a colored background. – egreg Sep 26 '14 at 13:45
  • @egreg True. I'll add that disclaimer. – Steven B. Segletes Sep 26 '14 at 13:49
  • However, this is the same as the \clipbox method. – egreg Sep 26 '14 at 13:50
  • @egreg I did not know that. Thanks for pointing it out. – Steven B. Segletes Sep 26 '14 at 13:55
  • @StevenB.Segletes Can you please explain a bit further? Should it be possible to run the command as \tleft{3cm}{longString} is long? While testing I think it worked at a time. But now I am getting the error ! Undefined control sequence. \\tleft [#1]#2#3->\setbox 0=\hbox {\x. I thought we don't have to use the def here? And why do you put the NEXT there? Is this third argument really necessary? – EverythingRightPlace Sep 26 '14 at 15:33
  • It isn't working for me. – EverythingRightPlace Oct 01 '14 at 16:21
  • @EverythingRightPlace Based on the prior comment's error message, it looks like you inadvertently added an extra backslash, as in \\tleft, instead of \tleft. Is that possible? – Steven B. Segletes Oct 01 '14 at 16:54
  • @StevenB.Segletes Please see the edit of the question. There is the code and the output. – EverythingRightPlace Oct 01 '14 at 16:59
  • @EverythingRightPlace Well, I see my problem, and that is I left \x in the \tleft macro definition, when it is an external (local) variable. Change the \x to #3. Then it compiles in your MWE, though you still might need a little work to get the right appearance. – Steven B. Segletes Oct 01 '14 at 17:06
  • minor note: some pdf previewers (skim on macos) leave tiny traces of removed characters on the right. others (acrobat on macos) do not. not a problem with the solution, but worth noting. – ivo Welch Apr 27 '21 at 21:23