RegExp match group not preceded by alphanumeric (\w) ignoring spaces

Viewed 111

I'm trying to match a group that only matches when the first non-spacing character preceding the match is NOT an alphanumeric character.

RegExp i've tried, consuming the spaces first with \s* then looking behind to check for \w:

(?<!\w)\s*\({\w+}\)

Success

Input:  this will = ({match})
Expected: ({match})
Actual: ({match})

Failure, still matches while preceded by alphanumeric (ignoring spaces)

Input:  this should = not ({match})
Expected: -
Actual: ({match})

Using \s+ instead of \s* solved it partially but now it requires at least one space which is not desired!

(?<!\w)\s+\({\w+}\)

I've been looking around the internet but cannot solve the problem. Anyone?

2 Answers

Use this solution (a mix of @horcrux and @Wiktor Stribizew suggestions):

<?php

$regex = '/(?<![\w\s])\s*(\({\w+}\))/';
$string = 'this will = ({match})
this should = not ({match})';
preg_match_all($regex, $string, $matches);
var_dump($matches[1]);

?>

See regex proof.

Results:

array(1) {
  [0]=>
  string(9) "({match})"
}

See PHP proof.

EXPLANATION

--------------------------------------------------------------------------------
  (?<!                     look behind to see if there is not:
--------------------------------------------------------------------------------
    [\w\s]                   any character of: word characters (a-z,
                             A-Z, 0-9, _), whitespace (\n, \r, \t,
                             \f, and " ")
--------------------------------------------------------------------------------
  )                        end of look-behind
--------------------------------------------------------------------------------
  \s*                      whitespace (\n, \r, \t, \f, and " ") (0 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    \(                       '('
--------------------------------------------------------------------------------
    {                        '{'
--------------------------------------------------------------------------------
    \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                             more times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
    }                        '}'
--------------------------------------------------------------------------------
    \)                       ')'
--------------------------------------------------------------------------------
  )                        end of \1

If there has to be a first non-spacing character present, you could match it and use \K to clear the match buffer.

[^\w\s]\h*\K\({\w+}\)

The pattern matches

  • [^\w\s] Match a single char other than a word char or whitespace char
  • \h*\K Match 0+ horizontal whitespace chars and forget what is matched so far
  • \({\w+}\) Match 1+ word chars between ({ and })

Regex demo | Php demo

Related