А почему именно на регекспах?
Можно сделать на Конечных автоматах чтото типа:
define( 'STATE_QUOTE_OPEN', 1 );
define( 'STATE_QUOTE_CLOSE', 2 );
define( 'STATE_LQUOTE_OPEN', 3 );
define( 'STATE_LQUOTE_CLOSE', 4 );
define( 'STATE_BRACE_OPEN', 5 );
define( 'STATE_BRACE_CLOSE', 6 );
function parse( $str, $repl ){
$state = 0; // default
$buf = '';
$brace_pos_start = 0;
for( $i = 0; $i < strlen( $str ); $i++ ){
switch( $str[$i] ){
case '"':
$state = $state == STATE_QUOTE_OPEN ? STATE_QUOTE_CLOSE : STATE_QUOTE_OPEN;
break;
case "'":
$state = $state == STATE_LQUOTE_OPEN ? STATE_LQUOTE_CLOSE : STATE_LQUOTE_OPEN;
break;
case '{':
if( $state != STATE_QUOTE_OPEN && $state != STATE_LQUOTE_OPEN ){
$state = STATE_BRACE_OPEN;
$buf = '';
$brace_pos_start = $i;
}
break;
case '}':
if( $state == STATE_BRACE_OPEN ){
$state = STATE_BRACE_CLOSE;
$str = substr_replace( $str, $repl[ $buf ], $brace_pos_start, $i - $brace_pos_start + 1 );
$i = $brace_pos_start + strlen( $repl[ $buf ] );
}
break;
default:
if( $state == STATE_BRACE_OPEN ) $buf .= $str[$i];
break;
}
}
return $str;
}
echo parse( 'SELECT * FROM {table} WHERE name="123 {qwerty} 789" AND id IN (SELECT id FROM {other_table})',
array( 'table' => 'tbl1', 'other_table' => 'tbl2' ) );
вывод:
SELECT * FROM tbl1 WHERE name=«123 {qwerty} 789» AND id IN (SELECT id FROM tbl2)
Сильно не пинайте, писалось на коленке в час ночи :)
Суть следующая, если открыта кавычка, то {...} не учитываем.
После замены сдвигаем курсор.