How to say, in a group match, "except if only whitespaces"?

Viewed 86

I would like to match text between quotes, but only if it consists of text and not only whitespaces.

In other words

hello world "this is matched" bonjour

should match this is matched, but

hello world "   " bonjour

should not match anything.

A previous question was almost what I wanted, except that it uses JS to make the test (this is also my current workaround in Python). OP's comment mentions negating \s but I do not think it was used anywhere (except as a comment)

Is there a simple way to add such a condition to the regex "(.+)"?

3 Answers

You might also use a capture group matching at least a single non whitespace char other than "

"(\s*[^\s"][^"]*)"

The pattern matches:

  • " Match literally
  • ( Capture group 1
    • \s*[^\s"] Match optional whitespace chars followed by a single non whitespace char other than "
    • [^"]* Optionally match any char except "
  • ) Close group
  • " Match literally

Regex demo

If there can be escaped double quotes, you might use an approach as also demonstrated in @anubhava's answer, matching any char except " or \ and allow matching an escaped character.

"(\s*[^\s"][^"\\]*(?:\\.[^"\\]*)*)"

Regex demo

You may use this regex (assuming your quotes are all balanced and unescaped):

(?<=")\s*[^"\s]*[^"\s][^"\n]*(?=")

RegEx Demo

RegEx Details:

  • (?<="): Assert that we have opening " just before current position
  • \s*: Match 0 or more whitespaces
  • [^"\s]*: Match 0 more of any character that are not " and not whitespace
  • [^"\s]: Match a character that is not " and not whitespace
  • [^"]*: Match 0 more of any character that is not "
  • (?="): Assert that we have closing " ahead

If you input may contain escaped quotes like \" then I would suggest using:

(?<=")(?!\s*")[^"\\\n]*(?:\\.[^"\\\n]*)*(?=")

RegEx Demo 2

This matches text within quotes, excludes the quotes, and is a no-match if there are only spaces within the quotes:

(?<=")(?!\s+")[^"]*(?=")

Examples:

hello world "this is matched" bonjour ==> match
hello world "singleWord" bonjour      ==> match
hello world "" bonjour (empty)        ==> match
hello world "  " bonjour (spaces)     ==> null

Explanation:

  • (?<=") - positive lookbehind for "
  • (?!\s+") - negative lookahead for 1+ spaces and a quote
    • if you want to have a no-match for empty text between quotes use (?!\s*")
  • [^"]* - scan over all chars until just before quotes
  • (?=") - positive lookahead for quotes
Related