Nadir Novruzov
Nadir Novruzov

Reputation: 477

RegEX not in brackets

I need to split text by pipe that is not in brackets. Here is the sample text

I {need|want|{ask|prefer}} you to {help {Jason|Maria|Santa|{Lucia|Raul}'s father}|go to school} 

I have found this /\|(?![^{]*})/g here: regex, extract string NOT between two brackets

now when i want to split this part of string by pipe

help {Jason|Maria|Santa|{Lucia|Raul}'s father}|go to school 

it also selects pipes between Jason, Maria, Santa because there is an opening bracket after them. How to change regex to match only pipe if it's not in any of the brackets.

test strings:

help {Jason|Maria|Santa|{Lucia|Raul}'s father}|go to school

should return

help {Jason|Maria|Santa|{Lucia|Raul}'s father}
go to school

.

Jason|Maria|Santa|{Lucia|Raul}'s father

should return

Jason
Maria
Santa
{Lucia|Raul}'s father

Upvotes: 2

Views: 222

Answers (1)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627517

You may use a SKIP-FAIL regex:

'~(\{(?:[^{}]++|(?1))*})(*SKIP)(*F)|\|~'

See the regex demo

Details

  • (\{(?:[^{}]++|(?1))*})(*SKIP)(*F) - match a substring that is between balanced curly braces and skip this match
    • (\{(?:[^{}]++|(?1))*}) - Capturing group 1 matching {, then 0+ repetitions of 1+ chars other than { and } or the whole Group 1 pattern is recursed ((?1) is a regex subroutine), and then } (balanced curly braces substring)
    • (*SKIP)(*F) - the PCRE verbs that make the regex engine fail the match and skip the matched text to proceed matching from the match end
  • | - or
  • \| - match a literal pipe to split with.

PHP demo:

$re = '~(\{(?:[^{}]++|(?1))*})(*SKIP)(*F)|\|~';
$str = "Jason|Maria|Santa|{Lucia|Raul}'s father";
print_r( preg_split($re, $str) );

Output:

Array
(
    [0] => Jason
    [1] => Maria
    [2] => Santa
    [3] => {Lucia|Raul}'s father
)

Upvotes: 3

Related Questions