user0103
user0103

Reputation: 1272

Split string on pipes which are not between square braces

I have this string:

EXAMPLE|abcd|[!PAGE|title]

I want to split it like this:

Array
(
    [0] => EXAMPLE
    [1] => abcd
    [2] => [!PAGE|title]
)

How to do it?

Upvotes: 0

Views: 1655

Answers (6)

mickmackusa
mickmackusa

Reputation: 47764

  1. Match and disqualify square brace wrapped substrings.
  2. Split on pipes.

Code: (Demo)

$txt = 'EXAMPLE|abcd|[!PAGE|title]';

var_export(
    preg_split('#\[[^]]*](*SKIP)(*FAIL)|\|#', $txt, 0, PREG_SPLIT_NO_EMPTY)
);

Output:

array (
  0 => 'EXAMPLE',
  1 => 'abcd',
  2 => '[!PAGE|title]',
)

Upvotes: 0

a3f
a3f

Reputation: 8657

A Non-regex solution:

$str = str_replace('[', ']', "EXAMPLE|abcd|[!PAGE|title]");
$arr = str_getcsv ($str, '|', ']')

If you expect things like this "[[]]", you would've to escape the inside brackets with slashes in which case regex might be the better option.

Upvotes: 0

burning_LEGION
burning_LEGION

Reputation: 13450

use this regex (?<=\||^)(((\[.*\|?.*\])|(.+?)))(?=\||$)

(?<=\||^) Positive LookBehind

    1st alternative: \|Literal `|`

    2nd alternative: ^Start of string

1st Capturing group (((\[.*\|?.*\])|(.+?))) 

    2nd Capturing group ((\[.*\|?.*\])|(.+?)) 

        1st alternative: (\[.*\|?.*\])

            3rd Capturing group (\[.*\|?.*\]) 

                \[ Literal `[`

                . infinite to 0 times Any character (except newline) 

                \| 1 to 0 times Literal `|`

                . infinite to 0 times Any character (except newline) 

                \] Literal `]`

        2nd alternative: (.+?)

            4th Capturing group (.+?) 

                . 1 to infinite times [lazy] Any character (except newline) 

(?=\||$) Positive LookAhead

    1st alternative: \|Literal `|`

    2nd alternative: $End of string

g modifier: global. All matches (don't return on first match)

Upvotes: 2

Javier Diaz
Javier Diaz

Reputation: 1830

DEMO

If you don't need anything more than you said, is like parsing a CSV but with | as separator and [ as " so: (\[.*?\]+|[^\|]+)(?=\||$) will do the work I think.

EDIT: Changed the regex, now it accepts strings like [asdf]].[]asf]

Explanation:

  1. (\[.*?\]+|[^\|]+) -> This one is divided in 2 parts: (will match 1.1 or 1.2)
    1.1 \[.*?\]+ -> Match everything between [ and ]
    1.2 [^\|]+ -> Will match everything that is enclosed by |
  2. (?=\||$) -> This will tell the regular expression that next to that must be a | or the end of the string so that will tell the regex to accept strings like the earlier example.

Upvotes: 3

Supericy
Supericy

Reputation: 5896

Given your example, you could use (\[.*?\]|[^|]+).

preg_match_all("#(\[.*?\]|[^|]+)#", "EXAMPLE|abcd|[!PAGE|title]", $matches);

print_r($matches[0]);

// output:
Array
(
    [0] => EXAMPLE
    [1] => abcd
    [2] => [!PAGE|title]
)

Upvotes: 2

Adder
Adder

Reputation: 5868

https://www.php.net/manual/en/function.explode.php

$array= explode('|', $string);

Upvotes: -5

Related Questions