RegEx is on the right path. Just include a +
modifier to greedily collect any trailing embedded brackets.
$str = '(aka "Beep My Dad Says" (2010)) (USA) (alternative title)';
/* Regex */
preg_match_all('!\(.*?\)+!',$str,$match);
var_dump($match[0]);
/*
array(3) {
[0] =>
string(31) "(aka "Beep My Dad Says" (2010))"
[1] =>
string(5) "(USA)"
[2] =>
string(19) "(alternative title)"
}
*/
But this will not work for other embedded quotes, and whitespace between segments should't be trusted. A primitive lexer might be a better approach.
$str = '(aka "Beep My (Dad) Says" (2010)) (USA)(alternative title)';
/* Lexer/Scanner */
$length = strlen($str);
$stack = array();
$cursor = $nested = 0;
$top = -1;
while ( $cursor < $length ) {
$c = $str[$cursor++]; // Grab char at index.
if ( '(' == $c ) { // Scan for starting character.
if ( !$nested ) // Check if this is the start of a new segment.
$stack[++$top] = ""; // Prototype new buffer (i.e. empty string).
$nested++; // Increase nesting.
}
if ( $nested )
$stack[$top] .= $c; // Append character, if inside brackets.
if ( ')' == $c ) // Scan for ending character.
$nested--; // Decrease nesting.
}
var_dump($stack);
/*
array(3) {
[0] =>
string(33) "(aka "Beep My (Dad) Says" (2010))"
[1] =>
string(5) "(USA)"
[2] =>
string(19) "(alternative title)"
}
*/
Again, this will just punt the problem down field, as fields that include uneven brackets will confuse any regular expression, or lexer.
$str = '(Sunn O))) "NN O)))" (2000)) (USA) (drone metal)';
Ideally, you would want to return to the source generator, and include escaping (if possible).
$str = '(aka "Beep My Dad Says" \(2010\)) (USA) (alternative title)';