Escapando caracteres especiais em expressões regulares do PHP

Suponha que queiramos que um caractere especial represente a si mesmo. Para isso, precisamos escapá-lo usando uma barra invertida. Vamos ver alguns exemplos.

Exemplo

No exemplo a seguir, o autor da expressão regular queria que o padrão de busca fosse: a letra 'a', seguida pelo sinal de mais '+', seguida pela letra 'x'. No entanto, o autor do código não escapou o caractere '+' e, portanto, o padrão de busca na verdade é: a letra 'a' uma ou mais vezes, depois a letra 'x':

php<?php
  $str = 'a+x ax aax aaax';
  $res = preg_replace('#a+x#', '!', $str);
?>

Como resultado, a variável conterá o seguinte:

php'a+x ! ! !'

Exemplo

Agora, o autor escapou o sinal de mais com uma barra invertida. Agora o padrão de busca está como deveria: a letra 'a', seguida pelo sinal de mais '+', seguida pela letra 'x'.

php<?php
  $str = 'a+x ax aax aaax';
  $res = preg_replace('#a\+x#', '!', $str);
?>

Como resultado, a variável conterá o seguinte:

php'! ax aax aaax'

Exemplo

Neste exemplo, o padrão é: a letra 'a', seguida pelo ponto '.', seguida pela letra 'x':

php<?php
  $str = 'a.x abx azx';
  $res = preg_replace('#a\.x#', '!', $str);
?>

Como resultado, a variável conterá o seguinte:

php'! abx azx'

Exemplo

No exemplo a seguir, o autor esqueceu de escapar a barra e a expressão regular capturou todas as substrings, pois o ponto não escapado representa qualquer caractere:

php<?php
  $str = 'a.x abx azx';
  $res = preg_replace('#a.x#', '!', $str);
?>

Como resultado, a variável conterá o seguinte:

php'! ! !'

Exemplo

Observe que se você se esquecer da barra invertida para o ponto (quando ele deve representar a si mesmo) - isso pode passar despercebido:

php<?php
  preg_replace('#a.x#', '!', 'a.x'); // retornará '!', como esperado
?>

Visualmente funciona corretamente (já que o ponto representa qualquer caractere, inclusive o próprio ponto '.'). Mas se alterarmos a string onde as substituições ocorrem - veremos nosso erro:

php<?php
  preg_replace('#a.x#', '!', 'a.x abx azx'); // retornará '! ! !', mas esperávamos '! abx azx'
?>