I came here with a complex string splitting problem similar to this, but none of the answers here did exactly what I wanted - so I wrote my own.
I am posting it here just in case it is helpful to someone else.
This is probably a very slow and inefficient way to do it - but it works for me.
function explode_adv($openers, $closers, $togglers, $delimiters, $str)
{
$chars = str_split($str);
$parts = [];
$nextpart = "";
$toggle_states = array_fill_keys($togglers, false); // true = now inside, false = now outside
$depth = 0;
foreach($chars as $char)
{
if(in_array($char, $openers))
$depth++;
elseif(in_array($char, $closers))
$depth--;
elseif(in_array($char, $togglers))
{
if($toggle_states[$char])
$depth--; // we are inside a toggle block, leave it and decrease the depth
else
// we are outside a toggle block, enter it and increase the depth
$depth++;
// invert the toggle block state
$toggle_states[$char] = !$toggle_states[$char];
}
else
$nextpart .= $char;
if($depth < 0) $depth = 0;
if(in_array($char, $delimiters) &&
$depth == 0 &&
!in_array($char, $closers))
{
$parts[] = substr($nextpart, 0, -1);
$nextpart = "";
}
}
if(strlen($nextpart) > 0)
$parts[] = $nextpart;
return $parts;
}
Usage is as follows. explode_adv
takes 5 arguments:
- An array of characters that open a block - e.g.
[
, (
, etc.
- An array of characters that close a block - e.g.
]
, )
, etc.
- An array of characters that toggle a block - e.g.
"
, '
, etc.
- An array of characters that should cause a split into the next part.
- The string to work on.
This method probably has flaws - edits are welcome.