1

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...

Community
  • 1
  • 1
Axel
  • 3,108
  • 10
  • 30
  • 49
  • 1
    Theoretical informatics says that this is not possible, the problem requires a turing machine, since it is non-regular (needs some form of mode or storage during the search). – arkascha Jun 29 '16 at 15:38
  • 1
    https://www.regex101.com/r/xY5rR3/3 – splash58 Jun 29 '16 at 15:45
  • 1
    Possible duplicate of [How to write a recursive regex that matches nested parentheses?](http://stackoverflow.com/questions/20569306/how-to-write-a-recursive-regex-that-matches-nested-parentheses) – Sebastian Proske Jun 29 '16 at 15:50
  • Indeed the duplicate matches my needs but as i'm not that good at regex-stuff i was not able to figure out which '(' and ')' change to '{' and '}'. – Axel Jun 29 '16 at 16:05
  • I made a little script to generate the pattern automatic while giving left and right limiter. See my answer at the bottom. – Axel Jul 13 '16 at 20:02

2 Answers2

2

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]);
Wiktor Stribiżew
  • 484,719
  • 26
  • 302
  • 397
0

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...

Axel
  • 3,108
  • 10
  • 30
  • 49