Drugi łańcuch nie działa ponieważ sprawdzanie jest wykonywane tylko 1 raz (w sensie, że przeszukuje jednokrotnie od początku do końca), a powinno być wykonywane rekurencyjnie. Ponieważ u Ciebie pierwszy znacznik [ b ] zawiera się w [ i ], w zmiennej \\2 zawarte jest wszystko co się znajduje pomiędzy znacznikami [ i ] i [ /i ], łącznie z [ b ] oraz [ /b ]. Następnie wyrażenie napotyka kolejny ciąg pasujący do wzorca czyli drugi znacznik [ b ], i też go zamienia. Więc na wyjściu jest sformatowany łańcuch bez pierwszego znacznika [ b ].
Teraz jeżeli użyjesz jeszcze raz funkcję preg_replace(), tylko z łańcuchem otrzymanym po poprzednim formatowaniu, na przykład tak:
Kod:
preg_replace($pattern,$replacement,preg_replace($pattern,$replacement,$string));
powinnieneś dostać już poprawny wynik.
Jednak aby lepiej zoptymalizować ten proces proponowałbym zmienić zarówno wzorzec, jak i to, na co będziemy zamieniać, przykładowo w taki sposób:
Kod:
$pattern="#\[([bi])](.*?)\[/\\1]#";
$replacement="<\\1>\\2</\\1>";
Natomiast samą zamianę zrobić w podobny sposób do tego:
Kod:
do {
$string = preg_replace($pattern,$replacement,$string,-1,$c);
} while ($c != 0);
Tak na marginesie, to wydaje mi się, że w Perlu jakoś prościej to się robi.
A swoją drogą to nie lepiej byłoby gdyby zamieniać same znaczniki, na przykład w taki sposób:
Kod:
$pattern="#\[(/)?([bi])]#";
$replacement="<\\1\\2>";