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.

Suppose i have a raw text defined as:

\newcommand{\rawtext}{this is some raw text with many words in it}

How to break this line after a given word or position? Of course, i only have access to \rawtext in the call site.

One possible solution is to prepend the n-th whitespace with \\, i simply don't know how.

share|improve this question
add comment

4 Answers 4

up vote 5 down vote accepted

You can also use the xstring package. No need to allocate a counter and to build a loop:

\documentclass{article}
\usepackage{xstring}
\newcommand\breakstring[2]{%
    \expandarg\StrCut[#2]{\noexpand#1}{ }\firstline\secondline
    \firstline\par\secondline}
\begin{document}
\breakstring{This is the story of Foo Bear}{3}
\end{document}

EDIT: to generalize the method, the second argument may contain a comma separated list of the numbers. Each of them is the number of words in a line:

\documentclass{article}
\usepackage{xstring}
\newcommand\breakstring[2]{%
    \saveexpandmode\expandarg
    \def\remaintext{#1}\def\listofcuts{#2,}%
    \loop
        \StrCut\listofcuts,\currentnumber\listofcuts
        \StrCut[\currentnumber]\remaintext\space\currentline\remaintext
        \currentline\par
        \unless\ifx\empty\listofcuts
    \repeat
    \remaintext
    \restoreexpandmode}
\begin{document}
\breakstring{Une petite cantate du bout des doigts obs\'edante et maladroite monte vers toi}{3,2,4,1}
\end{document}

which gives:

enter image description here

share|improve this answer
    
Unfortunately, \StrCut is not available on xstring v1.5d which is installed with TeXLive - Kubuntu 12.10. –  juliohm Mar 6 '13 at 17:33
    
To play with \StrCut, you need at least version 1.7 of xstring. Of course, it can be generalized to several lines but it requires to build a loop. Is it what the OP want? –  unbonpetit Mar 6 '13 at 17:36
    
@unbonpetit: Your answer is great, it's the cleanest. I'll accept it even though i can't reproduce with my current environment. Thanks. –  juliohm Mar 6 '13 at 21:41
add comment

A solution with LaTeX3 macros.

\documentclass{article}
\usepackage[margin=1cm,a4paper]{geometry} % wide text width
\usepackage{xparse}

\usepackage{kantlipsum}
\kantdef{\rawtext}{1} % some random text

\ExplSyntaxOn
\NewDocumentCommand{\breakafter}{mm}
 {
  \julio_breakafter:Nn #1 { #2 }
 }
\cs_new_protected:Npn \julio_breakafter:Nn #1 #2
 {
  % split the text into words, breaking at spaces
  \seq_set_split:NnV \l_julio_text_seq { ~ } #1
  % detach the last word
  \seq_pop_right:NN \l_julio_text_seq \l_tmpa_tl
  \int_zero:N \l_tmpa_int
  % start a mapping on the sequence
  \seq_map_inline:Nn \l_julio_text_seq
   {
    % print the word
    ##1
    % one step done
    \int_incr:N \l_tmpa_int
    % if the number of steps is a multiple of #2, add \\, else a space
    \int_compare:nTF { \int_mod:nn { \l_tmpa_int } { #2 } == 0 }
     { \\ }
     { ~ }
   }
   % print the last word (unskipping; the space will disappear if at line start
   \unskip \c_space_token \l_tmpa_tl
 }
\ExplSyntaxOff
\begin{document}
\breakafter\rawtext{8}

\breakafter\rawtext{16}

\end{document}

enter image description here

share|improve this answer
    
Thanks, LaTeX3 seems complicated, i never played with it. –  juliohm Mar 6 '13 at 17:13
1  
@juliohm It just needs some practice: the function names might be scaring at first, but the reasoning under the macros is straightforward. –  egreg Mar 6 '13 at 17:17
add comment

The stringstrings package can help, along with the command \breakstring, defined below

enter image description here

\documentclass{article}
\usepackage{stringstrings}

\newcounter{wordcount}
\newcommand\breakstring[2]{%
  \getargs{#1}%
  \setcounter{wordcount}{0}%
  \whiledo{\value{wordcount} < \narg}{%
    \addtocounter{wordcount}{1}%
    \csname arg\roman{wordcount}\endcsname%
    \ifthenelse{\value{wordcount} = #2}{\par}{ }%
  }
}

\begin{document}

\breakstring{This is the story of Foo Bear}{3}

\end{document}

But if you followed this link, Parsing a \$ as part of an improved \getargs command, you would find that you could replace \getargs with a much faster version, as follows. It really makes the parsing fast. I include its use with the same example below:

\documentclass{article}
%DITCH THE FOLLOWING LINE
%\usepackage{stringstrings}
%ADD THIS SECTION INSTEAD
\usepackage{ifnextok}
\usepackage{ifthen}
\makeatletter
\def\stringend{$}
\newcounter{arg@index}
\def\getargsFAST#1{\edef\argi{}\setcounter{arg@index}{1}%
                   \expandafter\parse@Block#1\stringend}

\def\parse@Block{\IfNextToken\stringend%
  {\edef\narg{\arabic{arg@index}}\@gobble}%
  {\IfNextToken\@sptoken{\addtocounter{arg@index}{1}%
   \expandafter\def\csname arg\roman{arg@index}\endcsname{}%
   \add@to{\parse@Block}}%
  {\add@to{\parse@Block}}}}

 \def\add@to#1#2{\expandafter\protected@edef\csname arg\roman{arg@index}\endcsname%
                   {\csname arg\roman{arg@index}\endcsname#2}#1}
\makeatother
%END OF ADD SECTION

\newcounter{wordcount}
\newcommand\breakstring[2]{%
  \getargsFAST{#1}%
  \setcounter{wordcount}{0}%
  \whiledo{\value{wordcount} < \narg}{%
    \addtocounter{wordcount}{1}%
    \csname arg\roman{wordcount}\endcsname%
    \ifthenelse{\value{wordcount} = #2}{\par}{ }%
  }
}

\begin{document}

\breakstring{This is the story of Foo Bear}{3}

\end{document}
share|improve this answer
add comment

The macro \breaktextat admits two arguments. The first one indicates at which spaces to break, as it may be a single number, or a comma separated list of numbers. The second argument is the text to break. The macro is declared "short" which means that the text to break should not contain empty lines or \par within it.

\documentclass{article}

% we try to make sure we don't overwrite anything
\newcommand*{\breakspacecount}{}
\newcount\breakspacecount
\newcommand*{\breaktextaux}{}
\newcommand*{\breakplace}{}
\newcommand*{\breaknexttoken}{}
\newcommand*{\myendmarker}{}
\def\myendmarker{\myendmarker}

\makeatletter
\newcommand*{\breaktexttest}{%
      \ifx\breaknexttoken\myendmarker
          \expandafter\@gobble\else
          \expandafter\breaktextaux\fi}

% first parameter=comma separated list of break places
% second parameter= the text (no empty line within)
\newcommand*{\breaktextat}[2]{%
      \def\breaktextaux ##1 %
         {##1\advance\breakspacecount 1 
          \@for\breakplace:=#1\do{\ifnum\breakspacecount=\breakplace
                                  \\\relax\fi}%
          \space
          \futurelet\breaknexttoken\breaktexttest}%
   \breakspacecount 0
   \breaktextaux #2 \myendmarker
}
\makeatother

\begin{document}\thispagestyle{empty}


\breaktextat{3}{this is some raw text with many words in it}


\breaktextat{1,3,5,8,11,14,18,22,26,31,36,41,47,53,59}
{Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut
purus elit, vestibulum ut, placerat ac, adipiscing vitae,
felis. Curabitur dictum gravida mauris. Nam arcu libero,
nonummy eget, consectetuer id, vulputate a, magna. Donec
vehicula augue eu neque. Pellentesque habitant morbi tristique
senectus et netus et malesuada fames ac turpis egestas. Mauris
ut leo. Cras viverra metus rhoncus sem. Nulla et lectus
vestibulum urna fringilla ultrices. Phasellus eu tellus sit
amet tortor gravida placerat. Integer sapien est, iaculis in,
pretium quis, viverra ac, nunc. Praesent eget sem vel leo
ultrices bibendum.}

% inserting more than one line:
\breaktextat{3,3,3,3}{this is some raw text with many words in it}
\end{document}

broken texts

share|improve this answer
add comment

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.