2

I'm aware of \makebox[*length*][s]{t e x t}, but I have to put spaces between each character. If I have a pretty long text it feels uncomfortable.

I've seen this answer by egreg and it works almost like I want. I'd like to specify the length as a first argument and pass the text without separating each letter individually as a second argument using xparse.

\spread{20em}{distribute this text}
\spread{5em}{word}

But, unfortunately, I was not managed to modify the code to make it work like I want. Could you help me with that?

1
  • So, specifying the inter-letter spacing is not good enough? You need to be able to specify the overall-length? If so, you know that will preclude line wrapping. May 7, 2020 at 13:21

2 Answers 2

1

First a simple solution that yields one space between letters and two between words:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\spreadtext}{mm}
 {
  \tl_set:Nx \l_tmpa_tl { #2 }
  \tl_replace_all:Nnn \l_tmpa_tl { ~ } { {} }
  \makebox[#1][s]
   {
    \skip_set:Nn \spaceskip { 0pt plus 1fill }
    \tl_map_inline:Nn \l_tmpa_tl { ##1 ~ } \unskip
   }
 }
\ExplSyntaxOff

\begin{document}

\spreadtext{20em}{distribute this text}

\spreadtext{5em}{word}

\end{document}

enter image description here

A slightly different one that has more space between words.

You can first split the input at spaces, then split each word at letters. Finally, typeset everything inserting a space between letters and a larger space between words.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\spreadtext}{mm}
 {
  \antshar_spread_text:nn { #1 } { #2 }
 }

\seq_new:N \l__antshar_spread_in_seq
\seq_new:N \l__antshar_spread_out_seq
\seq_new:N \l__antshar_spread_word_seq

\cs_new_protected:Nn \antshar_spread_text:nn
 {
  \seq_set_split:Nnn \l__antshar_spread_in_seq { ~ } { #2 }
  \seq_set_map:NNn \l__antshar_spread_out_seq \l__antshar_spread_in_seq { \antshar_spread_word:n { ##1 } }
  \makebox[#1][s]
   {
    \seq_use:Nn \l__antshar_spread_out_seq { \hspace{1em plus 0.5em minus 0.3em} }
   }
 }
\cs_new_protected:Nn \antshar_spread_word:n
 {
  \seq_set_split:Nnn \l__antshar_spread_word_seq { } { #1 }
  \seq_use:Nn \l__antshar_spread_word_seq { ~ }
 }
\ExplSyntaxOff

\begin{document}

\spreadtext{20em}{distribute this text}

\spreadtext{5em}{word}

\end{document}

enter image description here

A version that also copes with commands in the argument.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\spreadtext}{mm}
 {
  \antshar_spreadtext:nn { #1 } { #2 }
 }

\tl_new:N \l_antshar_spreadtext_tl

\cs_new_protected:Nn \__antshar_spreadtext_space:
 {
  \hspace{1em~plus~0.5em~minus~0.3em}
 }

\cs_new_protected:Nn \antshar_spreadtext:nn
 {
  \tl_set:Nn \l_antshar_spreadtext_tl { #2 }
  \regex_replace_all:nnN { \s } { \c{__antshar_spreadtext_space:} } \l_antshar_spreadtext_tl
  \regex_replace_all:nnN { (\w) } { \1 \  } \l_antshar_spreadtext_tl
  \regex_replace_all:nnN { \s(\c{.*}) } { \1  } \l_antshar_spreadtext_tl
  \tl_use:N \l_antshar_spreadtext_tl
 }
\ExplSyntaxOff

\begin{document}

\spreadtext{20em}{distribute \emph{this} text}

\spreadtext{5em}{word}

\end{document}

enter image description here

Without packages, but no command allowed:

\documentclass{article}

\makeatletter
\newcommand{\spreadtext}[2]{%
  \makebox[#1][s]{\spread@text#2\spread@text}%
}
\def\spread@text{\futurelet\next\spread@@text}
\def\spread@@text{%
  \ifx\next\spread@text
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\unskip\@gobble}%
  {\spread@@@text}%
}
\def\spread@@@text{%
  \ifx\next\@sptoken
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\spread@space}%
  {\spread@char}%
}
\def\spread@space#1{%
  \hspace{1em plus 0.5em minus 0.3em}%
  \spread@text#1%
}
\def\spread@char#1{#1 \spread@text}
\makeatother

\begin{document}

\spreadtext{20em}{distribute this text}

\spreadtext{5em}{word}

\end{document}
6
  • Thank you for the answer! I wonder whether it is possible make the xparse code more compact? Your answer about spreadign across the whole like looks way more shorter.
    – antshar
    May 10, 2020 at 22:01
  • @antshar Not sure what answer you're referring to.
    – egreg
    May 10, 2020 at 22:14
  • There is a hyperlink in the post to your answer. Here it is tex.stackexchange.com/a/253988/213149
    – antshar
    May 10, 2020 at 22:31
  • @antshar Oh, that one! I added it.
    – egreg
    May 10, 2020 at 22:42
  • Yes! Exactly what I wanted. Thank you so much!
    – antshar
    May 10, 2020 at 22:56
1

Using tokcycle, I provide two forms. In the first, the intercharacter spacing is specified. This is provided in the package example documentation. In the 2nd approach, using the syntax preferred by the OP, the user specifies the overall width of the string. Note that the target argument can contain formatting macros that are fully honored by \spread.

The disadvantage of \spread relative to \spaceouttext is that the former will not linebreak, whereas the latter will.

\documentclass{article}
\usepackage{tokcycle}
\newcommand\spaceouttext[2]{%
  \tokcycle{\addcytoks{##1\nobreak\hspace{#1}}}%
  {\processtoks{##1}}{\addcytoks{##1}}%
  {\addcytoks{##1\hspace{#1}}}{#2}%
  \the\cytoks\unskip}
\newcommand\spread[2]{%
  \tokcycle
  {\addcytoks{##1\hfill}}
  {\processtoks{##1}}
  {\addcytoks{##1}}
  {\addcytoks{##1\hfill}}{#2}%
  \makebox[#1]{\the\cytoks\unskip}%
}
\begin{document}
\spaceouttext{3pt plus 3pt}{This \textit{text \textbf{is} very} spaced
out}. Back to regular text.

\spaceouttext{1.5pt}{This \textit{text \textbf{is} somewhat} spaced
out}. Back to regular text.

\fbox{\spread{20em}{distribute \textit{this} text}}

\fbox{\spread{5em}{word}}
\end{document}

enter image description here

2
  • Thanks for spending time on that, but I don't want to use any additional packages apart from xparse. I just need to modify the linked answer, but I don't know how.
    – antshar
    May 7, 2020 at 13:51
  • 2
    @antshar I have never understood the imperative to avoid packages, but, of course, that is your call. May 7, 2020 at 14:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .