Axel
Axel

Reputation: 3323

How to get everything between brackets but only those, which are not wrapped into brackets themselves

By now i'm using regex: '/{(.*?)}/' to get everything inside curly barackets in strings like: 'abc {get me} def {and get me}' which works fine.

Now i'm looking for a way to exclude brackets, which are surrounded by brackets themselves. The string should be self-explanatory: 'abc {get me {!but not me!}} def {and get {!but not me again!} me} ghi'.

The following code should illustrate my needs...

<?php
$regex  = '/{(.*?)}/';
$string = 'abc {get me {!but not me!}} def {and get {!but not me again!} me} ghi';
preg_match_all( $regex, $string, $matches );
print_r( $matches[1] );
?>

prints:

Array
(
    [0] => get me {!but not me!
    [1] => and get {!but not me again!
)

but should be:

Array
(
    [0] => get me {!but not me!}
    [1] => and get {!but not me again!} me
)

Until now i was not able to find a solution via Google and looking forward to get one at SO.

regards

EDIT: Actually a very similar question was asked and answered on SO. But if you are not familiar with regex it's really hard to change from wrapper (...) to {...}. So you can not simply take the one pattern given by the answer (see link above) and search-replace all '(' & ')' with '{' & '}'. You really have to understand what's going on there.

But if you understand this pattern enough to customize it you probably would be able to write it on your own...

Upvotes: 1

Views: 103

Answers (2)

Axel
Axel

Reputation: 3323

Here is a script to generate the regex pattern with variable right and left delimiters.

$delimiter_wrap  = '~';
$delimiter_left  = '{';/* put YOUR left delimiter here.  */
$delimiter_right = '}';/* put YOUR right delimiter here. */

$delimiter_left  = preg_quote( $delimiter_left,  $delimiter_wrap );
$delimiter_right = preg_quote( $delimiter_right, $delimiter_wrap );
$pattern         = $delimiter_wrap . $delimiter_left
                 . '((?:[^' . $delimiter_left . $delimiter_right . ']++|(?R))*)'
                 . $delimiter_right . $delimiter_wrap;

/* Now you can use the generated pattern. */
preg_match_all( $pattern, $subject, $matches );

Credits: Thank you @Wiktor Stribiżew who wrote the answer i accepted...

Upvotes: 0

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627517

You need a recursive regex with a capturing group that would capture the contents inside the curly braces:

{((?:[^{}]++|(?R))*)}

Explanation:

  • { - a literal { (in PHP PCRE, you do not need to escape this character)
  • ( - Start of the capturing group 1
    • (?:[^{}]++|(?R))* - zero or more sequences (see (?:...)*) of 1+ characters other than { and } (see [^{}]++) or the whole pattern ((?R) is a placeholder for the whole pattern, like (?0) subroutine call)
  • ) - end of Group 1
  • } - closing literal }

See the regex demo and the PHP demo:

$re = '~{((?:[^{}]++|(?R))*)}~'; 
$str = "abc {get me {!but not me!}} def {and get {!but not me again!} me} ghi"; 
preg_match_all($re, $str, $matches);
print_r($matches[1]);

Upvotes: 2

Related Questions