Encaixe últimas linhas curtas ou longas em parágrafos perfeitamente retangulares

Encaixe últimas linhas curtas ou longas em parágrafos perfeitamente retangulares

Ao compor parágrafos, quero garantir que a última linha não seja excessivamente curtanemexcessivamente longo.Para esse fim, estou procurando configurações que produzam:

  • um parágrafo totalmente justificado e perfeitamente retangular;
  • um parágrafo justificado cuja última linha esteja preenchida com mais de 20% e menos de 80%.

Em outras palavras, nenhum parágrafo deve ter uma última linha preenchida em menos de 20% ou mais de 80% – em vez disso, eles devem ser totalmente justificados. O efeito poderia ser alcançado adicionando manualmente \parfillskip 0pt(apenas) esses parágrafos, mas é exatamente isso que quero automatizar.

Este documento mostra dois bons exemplos e dois maus exemplos:

\documentclass[a4paper]{article}
\usepackage[utf8]{inputenc}

% Page setup
\usepackage[a4paper,margin=3cm]{geometry}

% Typography
\usepackage{newtxtext,newtxmath}
\usepackage{microtype}
\parindent 0pt
\parskip\baselineskip

\begin{document}

\textbf{I'm looking for settings
        that produce either a)~a~perfect rectangle
        or b)~a paragraph whose last line
        is filled more than 20\% and less than 80\%.}

\section*{Good examples}

\textbf{My perfect paragraph is a~rectangle:}

{
\parfillskip 0pt
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed rhoncus lorem eget ultricies bibendum. Duis luctus felis arcu, sit amet dapibus orci imperdiet id. Duis ullamcorper tortor eget leo fringilla, a lacinia nisl pulvinar. Etiam id facilisis augue. Sed convallis tempus ex, sed accumsan justo pulvinar vitae. Sed id sapien leo. Aliquam posuere ex lacus, ut posuere metus ullamcorper eu. Duis a imperdiet nibh. Donec tincidunt hendrerit nulla, et convallis metus imperdiet nec. Pellentesque massa enim, pharetra in pulvinar a, efficitur nec lorem. Cras mattis ex lorem, et euismod ligula rhoncus. Aenean ultricies quis velit non faucibus.

}

\textbf{However, this is not always achievable (and that's fine):}

{
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed rhoncus lorem eget ultricies bibendum. Duis luctus felis arcu, sit amet dapibus orci imperdiet id. Duis ullamcorper tortor eget leo fringilla, a lacinia nisl pulvinar. Etiam id facilisis augue. Sed convallis tempus ex, sed accumsan justo pulvinar vitae. Sed id sapien leo. Aliquam posuere ex lacus, ut posuere metus ullamcorper eu. Duis a imperdiet nibh. Donec tincidunt hendrerit nulla, et convallis metus imperdiet nec. Pellentesque massa enim, pharetra in pulvinar a, efficitur nec lorem. Cras mattis ex lorem, et euismod ligula rhoncus.

}

\section*{Bad examples}

\textbf{This last line is too short:}

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed rhoncus lorem eget ultricies bibendum. Duis luctus felis arcu, sit amet dapibus orci imperdiet id. Duis ullamcorper tortor eget leo fringilla, a lacinia nisl pulvinar. Etiam id facilisis augue. Sed convallis tempus ex, sed accumsan justo pulvinar vitae. Sed id sapien leo. Aliquam posuere ex lacus, ut posuere metus ullamcorper eu. Duis a imperdiet nibh. Donec tincidunt hendrerit nulla, et convallis metus imperdiet nec. Pellentesque massa enim, pharetra in pulvinar a, efficitur nec lorem.

\textbf{The above can be fixed with}
\verb!\parfillskip 0pt plus 0.80\textwidth!
\textbf{but that doesn't help for the case below.}

\textbf{This last line should have been justified (note the small gap at the end):}

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed rhoncus lorem eget ultricies bibendum. Duis luctus felis arcu, sit amet dapibus orci imperdiet id. Duis ullamcorper tortor eget leo fringilla, a lacinia nisl pulvinar. Etiam id facilisis augue. Sed convallis tempus ex, sed accumsan justo pulvinar vitae. Sed id sapien leo. Aliquam posuere ex lacus, ut posuere metus ullamcorper eu. Duis a imperdiet nibh. Donec tincidunt hendrerit nulla, et convallis metus imperdiet nec. Pellentesque massa enim, pharetra in pulvinar a, efficitur nec lorem. Cras mattis ex lorem, et euismod ligula rhoncus. Aenean ultricies quis velit non ut faucibus.

\textbf{The above can be fixed with}
\verb!\parfillskip 0pt!
\textbf{but that doesn't help for the case below.}

\end{document}

Uma solução deve consistir emajustes apenas no preâmbulo. Nenhum comando especial deve ser necessário no início ou no final de qualquer parágrafo. Espero que, como em vários casos relacionados, isso possa ser resolvido com um pouco de cola especial \parfillskip, mas não tenho certeza se isso é possível.


Perguntas relacionadas, cujas soluções tentei, mas não produziram o resultado pretendido:

Responder1

Esta abordagem ésemi-automático, pois ainda é necessário incluir o parágrafo em uma \fixitmacro.

ABORDAGEM REVISADA

Em vez de dissecar o parágrafo palavra por palavra, como na ABORDAGEM ORIGINAL abaixo, aqui, eu apenas meço o comprimento do \hboxmaterial do parágrafo e decido, com base no comprimento, se devo empregar um final \hspace{}\mboxe/ou um \parfillskip0pt.

A macro fornece um argumento opcional se forem necessários ajustes. Representa a maior saturação de linha fracionária que será comprimida, atualmente definida como .05(5%). Você saberá que precisa de ajustes se uma linha que você pensou que seria comprimida for expandida para uma nova linha totalmente espaçada. Definir o valor padrão como .0eliminará quaisquer problemas, mas às custas de que algumas linhas que poderiam ser compactadas para eliminar as viúvas finais sejam expandidas para que a viúva ocupe 20% da linha subsequente.

\documentclass{article}
\usepackage[margin=1.5in,top=0cm,bottom=0cm]{geometry}
\newcommand\fixit[2][.05]{%
  \setbox0=\hbox{\hspace{\parindent}#2}\fixithelp{#1}{#2}}
\newcommand\fixithelp[2]{%
  \wd0=\dimexpr\wd0-\linewidth\relax%
  \ifdim\wd0>0pt\relax%
    \fixithelp{#1}{#2}%
  \else%
    \wd0=\dimexpr\wd0+\linewidth\relax
    \ifdim\wd0>.9\linewidth\relax%
      {\parfillskip0pt\relax#2\par}%
    \else%
      \ifdim\wd0>.8\linewidth\relax%
        {\parfillskip0pt\relax#2\hspace{.2\linewidth}\par}%
      \else%
        \ifdim\wd0<#1\linewidth\relax%
          {\parfillskip0pt\relax#2\par}%
        \else%
          \ifdim\wd0<.2\linewidth\relax%
            {\parfillskip0pt\relax#2\hspace{.8\linewidth}\mbox{}\par}%
          \else%
            #2%
          \fi
        \fi
      \fi
    \fi
  \fi%
}
\sloppy
\parskip1ex
\begin{document}
\noindent\rule{.2\linewidth}{2pt}\hfill\rule{.2\linewidth}{2pt}

\fixit{%
yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yackity yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yackity yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yack, yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yackity yack, yakity yack, yakity yack, paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\end{document}

Margens = 1,5 pol.

insira a descrição da imagem aqui

Margens = 1,7 pol.

insira a descrição da imagem aqui

Margens = 1,9 pol.

insira a descrição da imagem aqui

ABORDAGEM ORIGINAL

Mas o que a macro faz é regurgitar o parágrafo palavra por palavra até chegar às últimas 4 palavras. Em seguida, ele determina quantas dessas últimas palavras devem ser excedidas .2\linewidthe as agrupa dentro de an \mboxjunto com a \hspace{.2\linewidth}. Se as últimas 3 palavras não excederem .2\linewidth, ele usará todas as 4 no \mbox.

Para o que o OP solicita, \sloppyquase certamente será necessário, já que estamos falando em alterar o comprimento do texto de .4\linewidthuma só vez (o que quase sempre é algo indesejável). Então eu adicionei.

Uma coisa que quebrará a abordagem é se um grupo aberto anteriormente terminar nas últimas 4 palavras do parágrafo. Isso se aplicaria, por exemplo, ao fechar uma posição longa \textitperto do final de um parágrafo.

A outra coisa a notar é que um parágrafo perfeitamente retangularnuncaser criado com esta abordagem, por causa do adicionado \hspaceno final do parágrafo.

\documentclass{article}
\newcommand\fixit[1]{\fixithelp#1 \cr\relax}
\def\fixithelp#1 #2 #3 #4 #5\relax{\ifx \cr#5\finishup#1 #2 #3 #4\relax%
  \else#1 \fixithelp#2 #3 #4 #5\relax\fi}
\def\finishup#1 #2 #3 #4\relax{ %
  \setbox0=\hbox{#4}%
  \ifdim\wd0>.2\linewidth\relax #1 #2 #3 \mbox{#4\hspace{.2\linewidth}}\else%
    \setbox0=\hbox{#3 #4}%
    \ifdim\wd0>.2\linewidth\relax #1 #2 \mbox{#3 #4\hspace{.2\linewidth}}\else%
      \setbox0=\hbox{#2 #3 #4}%
      \ifdim\wd0>.2\linewidth\relax #1 \mbox{#2 #3 #4\hspace{.2\linewidth}}\else%
        \mbox{#1 #2 #3 #4\hspace{.2\linewidth}}%
      \fi%
    \fi%
  \fi%
}
\sloppy
\parskip1em
\begin{document}
\fixit{typesetting 
paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce either:}

\fixit{%
paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce overlylongwords:}

\fixit{%
I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce overlylongwords:}

\fixit{%
typesetting paragraphs, I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce I I I I:}

\fixit{%
typesetting I want to \textit{ensure their last line} is neither 
overly short nor overly long. To that end, I'm looking for settings that 
produce I I I I:}
\end{document}

insira a descrição da imagem aqui

informação relacionada