Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to have a command that truncates text like

'An example sentence.'

to

'...ple sentence.'.

When called like this

\truncateToLeft{4cm}{An example sentence.}

I have no idea how to implement that (I do not understand /usr/share/texmf-dist/tex/latex/truncate/truncate.sty).

Edit: A (VERY MINOR) thing I noticed with the answers below, is that the text is not cut at 'letter-borders'. Just to ask (I'm no (La)TeX-Expert): Is it possible to cut the text at 'letter-borders'? --> This is solved by Steven B. Segletes second answer!

share|improve this question

3 Answers 3

up vote 18 down vote accepted

Just for fun, here is another way. While not specified in meaning, I took your length in argument #1 to be the length that remains, rather than the length that is clipped.

THIS ANSWER HAS TWO PARTS: the first answer clips the string mid-character to the specified length; and the second answer clips to the nearest character boundary inside the specified length (while allowing font declarations in the text).

PART 1

The solution relies on the fact that \ldots is wider than any single character. The approach is to recursively strip off letters from the beginning of the sentence, until the result is less wide than the target width. Then, after an \ldots, one takes the prior result (which is just slightly larger than the target width, and sets it in a right-aligned box of the target width. This will make the extra portion of the left-most character overlap the right end of the \ldots. To take care of this small mismatch, the \ldots are again lapped to the left in a white colorbox, to get rid of the overhang.

Finally, the result is re-kerned to the right to bring you to the end of the printed result (this last phase was an EDIT, upon realizing that I left the current position too far to the left.

EDITED to streamline code and remove a pathological case if null argument was passed to \clip.

\documentclass{article}
\usepackage{xcolor}
\newlength\cliplength
\newcommand\clip[2]{\setlength\cliplength{#1}\cliphelper#2\relax\relax}
\def\cliphelper#1#2\relax{%
  \fboxsep 0pt%
  \setbox0=\hbox{#2}%
  \ifdim\wd0>\cliplength%
    \cliphelper#2\relax%
  \else%
    \setbox0=\hbox{#1#2}%
    \ldots\makebox[\cliplength][r]{\box0}%
    \kern-\cliplength\llap{\colorbox{white}{\strut\ldots}}%
    \kern\cliplength%
  \fi%
}
\parindent 0in
\begin{document}
\ldots\rule{1cm}{1pt}

\clip{1cm}{An example sentence.}

\ldots\rule{2cm}{1pt}

\clip{2cm}{An much longer example sentence.}

\ldots\rule{3cm}{1pt}

\clip{3cm}{An much longer example sentence.}

\end{document}

enter image description here


PART 2

The OP later wondered if the clipping could occur at letter boundaries. That problem is actually easier, can be done without xcolor, and requires but a small change in my routine \cliphelper. In this case, once the test string becomes less wide than the target clip width, I just set \ldots and the test string. Here is the MWE which will clip to the closest letter boundary that is at or slightly smaller than the target clipping width:

REEDITED to support font size/shape declaration macros (that don't take arguments).

\documentclass{article}
\newlength\cliplength
\newcommand\clip[2]{%
  \def\savedmacro{}\setlength\cliplength{#1}\cliphelper#2\relax\relax}
\def\cliphelper#1#2\relax{%
  \setbox0=\hbox{\savedmacro#2}%
  \ifdim\wd0>\cliplength% Is length larger than \cliplength?
    \savethemacros{#1}{#2}% If #1 is a macro, save it
    \cliphelper#2\relax% Recursively clip next letter
  \else%
    \ldots\savedmacro#2% Final typeset, once string length below \cliplength
  \fi%
}
\makeatletter
\def\savethemacros#1#2{%
  \ifcat A\noexpand#1\else\ifcat 1\noexpand#1\else% Skip cat11 and cat12
      \protected@edef\savedmacro{\savedmacro#1}% Save the macro
  \fi\fi%
}
\makeatother
\begin{document}
\ldots\rule{1cm}{1pt}\par
\clip{1cm}{An example sentence.}

\ldots\rule{2cm}{1pt}\par
\clip{2cm}{An much longer example sentence.}

\ldots\rule{3cm}{1pt}\par
\clip{3cm}{An much longer example sentence.}

\ldots\rule{1cm}{1pt}\par
\clip{1cm}{An \bfseries\itshape example sentence.\normalfont}

\ldots\rule{2cm}{1pt}\par
\clip{2cm}{An much longer example \bfseries sentence\normalfont.}

\ldots\rule{3cm}{1pt}\par
\clip{3cm}{\large An much \itshape longer example \bfseries\tiny sentence\normalfont.}

\end{document}

enter image description here

share|improve this answer
    
Well, what can I say? I am impressed :) Thank you so much for your effort. It is a pity that one can only 'accept' one answer. I voted up what was possible with my small reputation :D –  MCH Apr 30 at 21:48
    
@MCH Thank you. I have added some explanation of the logic, and made a slight change to the algorithm, since it left the cursor not at the right-end of the sentence. –  Steven B. Segletes Apr 30 at 23:38
    
@MCH Addendum added to respond to your latter question about clipping at letter boundaries. –  Steven B. Segletes Apr 30 at 23:59
    
Your second solution almost perfectly fits my needs :) One thing I noticed though: \clip{1cm}{\footnotesize \textbf{An example sentence.}} yields the same as \clip{1cm}{An example sentence.} I guess it strips off the '\footnotesize \textbf{'. Has this something to do with setbox? I should really read the TeX-Book I ordered ... –  MCH May 1 at 14:19
1  
@MCH Please see revision for 2nd piece of code. –  Steven B. Segletes May 1 at 15:38

enter image description here

\documentclass{article}
\usepackage{trimclip}
\begin{document}


\ldots\clipbox{{\width - 1cm} 0pt 0pt 0pt}{An example sentence.}

\end{document}
share|improve this answer
    
Thank you very much for your answer :) –  MCH Apr 30 at 20:51
    
Although your answer is the way to go for me, I decided to accept Steven B. Segletes answer because it required so much effort. I hope this is okay for you :) –  MCH Apr 30 at 21:59
8  
@MCH oh no, how am I ever going to catch up with egreg:-) –  David Carlisle May 1 at 7:34
    
@DavidCarlisle : Too bad that you don't get credit for "useful comments" ... –  ClintEastwood May 6 at 22:39

ConTeXt provides a macro \limitatetext for truncating text to a given width. You can set the width to be negative to get the desired behavior. For example:

\limitatetext{An example sentence}{-3cm}{\unknown}

gives

enter image description here

This always cuts the text at 'letter borders'.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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