Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I remove blank lines from a block of text with regex?

Quick answer

For LF or CRLF text, match a line containing only spaces or tabs and its line ending. In Python, use re.sub(r'(?m)^[ \t]*\r?\n', '', text); in JavaScript, use text.replace(/^[ \t]*\r?\n/gm, ''). The multiline setting lets ^ match each line, and the global replacement removes repeated matches. A final blank line without a line ending needs separate handling.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

What pattern removes blank lines but leaves every line that has text?

Geez

For text separated by LF (\n) or CRLF (\r\n), match a line made of zero or more spaces or tabs, followed by its line ending. The pattern is ^[ \t]*\r?\n: ^ marks the start of a line, [ \t]* accepts spaces or tabs (including none), and \r?\n matches LF with an optional preceding carriage return.

In Python, enable multiline mode with (?m) inside the pattern. In JavaScript, use the m flag so ^ works at line starts, and the g flag to replace every match. Python’s re.sub() and JavaScript’s replace() then substitute an empty string for those matches. [S1] [S2]

This handles lines containing spaces or tabs, not every character that a language might consider whitespace. It also does not match a whitespace-only final line if that line has no terminating newline; handle that case deliberately if your input can have one. [S1] [S2]

Follow-up question

Can you show the before and after, including a whitespace-only line?

Geez

Assume the input uses LF newlines. Here, the second line contains spaces, and the tab before plum is part of a nonblank line:

Before (visible markers show line endings and whitespace): apple\n, ··\n, pear\n, →plum

After: apple\n, pear\n, →plum

The markers ·· and → are explanatory stand-ins for spaces and a tab; they are not literal characters in the input. The pattern consumes the blank line’s newline too, so it removes that line without deleting neighboring text. With CRLF input, the optional \r lets the same patterns match the carriage return before \n. [S1] [S2]

Follow-up question

What does the code look like in Python and JavaScript?

Geez

Here is the same assumed input and operation in each language:

Python:

import re

text = "apple\n  \npear\n\tplum"
cleaned = re.sub(r'(?m)^[ \t]*\r?\n', '', text)
print(cleaned)

JavaScript:

const text = "apple\n  \npear\n\tplum";
const cleaned = text.replace(/^[ \t]*\r?\n/gm, "");
console.log(cleaned);

Both produce apple\npear\n\tplum: the spaces-only line is removed, while the tab before plum stays because that line has text. Python’s (?m) activates multiline anchors; JavaScript’s m does that, and g makes replace() process repeated matches. These are language-specific flags and APIs, not interchangeable syntax. [S1] [S2]

Follow-up question

What should I check if an empty line remains or the output changes unexpectedly?

Geez

First check the input’s actual line endings and what you mean by “blank.” These patterns target LF or CRLF lines containing only spaces or tabs. They do not establish behavior for every newline convention or every Unicode whitespace character. [S1] [S2]

Then check whether the final blank line has a newline after it. A trailing whitespace-only line without a line ending is a separate case; the shown patterns intentionally require one. If you want to remove that too, define the desired treatment of trailing spaces and a final empty line before changing the pattern. Test on a small copy and compare the result, especially if preserving the number of trailing newlines matters.

A practical checklist

  • Confirm whether the input uses LF or CRLF line endings.

  • Decide whether “blank” means empty or spaces-and-tabs-only.

  • Use Python (?m) or JavaScript’s m flag for line-start matching.

  • Use JavaScript’s g flag to remove every matching line.

  • Check separately for a final whitespace-only line without a newline.

  • Test a small sample and verify that nonblank lines and intended trailing newlines remain.

A few more useful answers

Why is the `m` flag needed in JavaScript?

Without multiline mode, ^ matches the start of the whole input, rather than each line. The m flag makes it match line boundaries; g is separate and applies replacements to repeated matches. [S2]

Will this remove lines containing nonbreaking spaces?

Not with [ \t]*: that character class matches ordinary spaces and tabs only. The supplied references do not establish a pattern for all Unicode whitespace, so identify the characters in your input and choose a suitable approach.

Does the pattern remove a final empty line?

It removes a blank line when that line has a matching line ending. A final whitespace-only line without a terminating newline needs a deliberate additional case. [S1] [S2]

Sources

References used for this guide.

  1. [S1] Python 3 regular-expression operations: multiline anchors and substitution
    docs.python.org · Checked
  2. [S2] MDN: JavaScript regular-expression flags and multiline behavior
    developer.mozilla.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work