<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: TextBases</title>
    <description>The latest articles on DEV Community by TextBases (@textbases).</description>
    <link>https://dev.to/textbases</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4053453%2F5b6624fb-b015-4809-8450-7ffd2c2fa746.png</url>
      <title>DEV Community: TextBases</title>
      <link>https://dev.to/textbases</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/textbases"/>
    <language>en</language>
    <item>
      <title>How to Remove Line Breaks from Copied PDF Text Without Destroying Paragraphs</title>
      <dc:creator>TextBases</dc:creator>
      <pubDate>Wed, 29 Jul 2026 14:45:39 +0000</pubDate>
      <link>https://dev.to/textbases/how-to-remove-line-breaks-from-copied-pdf-text-without-destroying-paragraphs-3dh1</link>
      <guid>https://dev.to/textbases/how-to-remove-line-breaks-from-copied-pdf-text-without-destroying-paragraphs-3dh1</guid>
      <description>&lt;p&gt;Copying text from a PDF often produces something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The copied paragraph looks normal
inside the PDF, but every visual line
becomes a hard line break after pasting.

The next paragraph should remain
separate from the first one.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you usually want is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The copied paragraph looks normal inside the PDF, but every visual line becomes a hard line break after pasting.

The next paragraph should remain separate from the first one.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is not simply “remove all line breaks.”&lt;/p&gt;

&lt;p&gt;The real goal is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Join wrapped lines inside a paragraph while preserving line breaks that carry meaning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction matters because PDF text can contain paragraphs, headings, lists, citations, addresses, tables, code, and multi-column layouts. A cleanup rule that works perfectly for prose can damage structured content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why copied PDF text contains hard line breaks
&lt;/h2&gt;

&lt;p&gt;A PDF is primarily a page-layout format.&lt;/p&gt;

&lt;p&gt;Text may be positioned using coordinates, columns, text boxes, captions, footnotes, and visual line endings. When you copy it, the clipboard may preserve those visual boundaries as newline characters.&lt;/p&gt;

&lt;p&gt;Depending on the source and operating system, the pasted text may contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;\n&lt;/code&gt; — line feed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\r\n&lt;/code&gt; — carriage return plus line feed&lt;/li&gt;
&lt;li&gt;blank lines represented by two or more newline sequences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A normal paragraph can therefore become a list of short physical lines even though it should be one continuous block of text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the obvious replacement is dangerous
&lt;/h2&gt;

&lt;p&gt;A common first attempt is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This replaces every whitespace sequence with one space.&lt;/p&gt;

&lt;p&gt;It may look convenient, but it also destroys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;paragraph boundaries&lt;/li&gt;
&lt;li&gt;list formatting&lt;/li&gt;
&lt;li&gt;code indentation&lt;/li&gt;
&lt;li&gt;addresses&lt;/li&gt;
&lt;li&gt;table-like text&lt;/li&gt;
&lt;li&gt;intentionally separated sections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another common attempt is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\r?\n&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This preserves tabs and some other whitespace, but it still merges every line, including real paragraph breaks.&lt;/p&gt;

&lt;p&gt;For plain prose, a better strategy is to protect paragraph boundaries first.&lt;/p&gt;

&lt;h2&gt;
  
  
  A paragraph-preserving JavaScript approach
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cleanPdfText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;
    &lt;span class="c1"&gt;// Normalize Windows and old Mac line endings&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\r\n?&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Temporarily protect blank-line paragraph boundaries&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n[\t&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;__PARAGRAPH_BREAK__&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Join remaining single line breaks&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\t&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\n[\t&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Normalize repeated spaces&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;\t]{2,}&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Restore paragraphs&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/__PARAGRAPH_BREAK__/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copied&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`The copied paragraph looks normal
inside the PDF, but every visual line
becomes a hard line break after pasting.

The next paragraph should remain
separate from the first one.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cleanPdfText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;copied&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The copied paragraph looks normal inside the PDF, but every visual line becomes a hard line break after pasting.

The next paragraph should remain separate from the first one.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is still a heuristic, not a full PDF-layout parser. It assumes that blank lines represent real paragraph boundaries and single newlines represent wrapped prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same idea in Python
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_pdf_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\n[\t ]*\n+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__PARAGRAPH_BREAK__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;joined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[\t ]*\n[\t ]*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;protected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;compact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ \t]{2,}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;joined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__PARAGRAPH_BREAK__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logic is intentionally simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Normalize newline styles.&lt;/li&gt;
&lt;li&gt;Protect blank-line paragraph boundaries.&lt;/li&gt;
&lt;li&gt;Replace remaining single newlines with spaces.&lt;/li&gt;
&lt;li&gt;Normalize repeated spaces.&lt;/li&gt;
&lt;li&gt;Restore the paragraphs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Watch for hyphenated words
&lt;/h2&gt;

&lt;p&gt;PDF text can also split a word across lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The formatter should preserve mean-
ing while cleaning the copied text.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blindly joining the lines produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The formatter should preserve mean- ing while cleaning the copied text.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might be tempted to remove every hyphen followed by a line break:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can work for some words, but it can also break valid hyphenated terms.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;client-
side
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;may be intended as &lt;code&gt;client-side&lt;/code&gt;, not &lt;code&gt;clientside&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A safer workflow is to flag these cases for review rather than assuming every end-of-line hyphen should disappear.&lt;/p&gt;

&lt;p&gt;You can detect them with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;possibleSplitWords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Za-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;\r?\n[&lt;/span&gt;&lt;span class="sr"&gt;A-Za-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then review the matches manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cases that should not be cleaned automatically
&lt;/h2&gt;

&lt;p&gt;Do not apply a prose-oriented newline rule blindly to:&lt;/p&gt;

&lt;h3&gt;
  
  
  Lists
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Install the dependency
- Run the build
- Check the output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Addresses
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TextBases
123 Example Street
Singapore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Citations and references
&lt;/h3&gt;

&lt;p&gt;Line placement may separate authors, publication titles, page numbers, or identifiers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tables and financial data
&lt;/h3&gt;

&lt;p&gt;Columns can collapse into one unreadable sentence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Poetry, lyrics, and legal clauses
&lt;/h3&gt;

&lt;p&gt;Line boundaries may be part of the intended meaning or structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-column PDFs
&lt;/h3&gt;

&lt;p&gt;Copied text can jump between columns in the wrong order. Removing line breaks cannot reconstruct the original reading sequence.&lt;/p&gt;

&lt;h2&gt;
  
  
  A safer cleanup workflow
&lt;/h2&gt;

&lt;p&gt;A reliable workflow is intentionally conservative:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy one small section from the PDF.&lt;/li&gt;
&lt;li&gt;Check whether the text is ordinary prose or structured content.&lt;/li&gt;
&lt;li&gt;Preserve blank lines that represent real paragraphs.&lt;/li&gt;
&lt;li&gt;Join only the wrapped lines inside those paragraphs.&lt;/li&gt;
&lt;li&gt;Review end-of-line hyphens.&lt;/li&gt;
&lt;li&gt;Check punctuation and spacing.&lt;/li&gt;
&lt;li&gt;Compare the result with the source PDF.&lt;/li&gt;
&lt;li&gt;Repeat section by section.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For quick prose cleanup, I use the free &lt;a href="https://textbases.app/text-tools/remove-line-breaks/" rel="noopener noreferrer"&gt;TextBases Remove Line Breaks tool&lt;/a&gt;. It is useful when I do not need to write a script, while the code examples above are better when the cleanup needs to be part of a repeatable workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  A useful decision rule
&lt;/h2&gt;

&lt;p&gt;Use automatic cleanup when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the input is ordinary paragraph text&lt;/li&gt;
&lt;li&gt;single newlines are clearly caused by visual wrapping&lt;/li&gt;
&lt;li&gt;blank lines reliably separate paragraphs&lt;/li&gt;
&lt;li&gt;you can compare the output with the source&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use manual review when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;formatting carries meaning&lt;/li&gt;
&lt;li&gt;the PDF contains columns, tables, citations, or footnotes&lt;/li&gt;
&lt;li&gt;words are split across line endings&lt;/li&gt;
&lt;li&gt;the text will be used in legal, financial, medical, academic, or customer-facing work&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Removing line breaks is easy.&lt;/p&gt;

&lt;p&gt;Knowing which line breaks should remain is the actual problem.&lt;/p&gt;

&lt;p&gt;The safest solution is not the most aggressive regex. It is a small, understandable transformation that preserves paragraphs and makes uncertain cases visible for human review.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
