9

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}. – user31729 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 – user31729 Sep 26 '14 at 13:30
9

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.

  • This may work for a text with whitespace but not for my task: cutting a long string (no spaces). – EverythingRightPlace Sep 26 '14 at 15:43
  • @EverythingRightPlace use the option breakwords. – Yiannis Lazarides Sep 26 '14 at 15:58
  • In general it works, although there are those dots (e.g. output thisIsSoExtr...). This wouldn't be a problem. Still it isn't working in the table environment. Please see the edit of my question, beforehand I simplified too much. – EverythingRightPlace Sep 26 '14 at 16:08
  • @EverythingRightPlace There is no problem in a tabular, have you tried it? – Yiannis Lazarides Sep 26 '14 at 16:15
  • I am trying all the time. Now I am losing countenance... weekend delayed :P – EverythingRightPlace Sep 26 '14 at 16:22
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

  • 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
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!)

  • 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

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.