Word boundaries
Um problema comum é que uma expressão regular que casa com a palavra que você quer pode muitas vezes casar também
onde a "palavra" faz parte de uma palavra maior. Exemplo: se você quiser pesquisar apenas a palavra por e
usar a expressão regular por
, você pode não obter o resultado desejado (você pode casar também com
proporcionar ou porém, por exemplo).
Para resolver esse problema, uma solução é usar a metasequência \b
. Ela faz parte de uma categoria
chamada word boundaries, que trata dos limites de início e fim de palavras. Word boundaries, assim como âncoras,
também casam com posições em uma string, ao invés de caracteres.
A word boundary \b
casa com o início ou o fim de uma palavra. Falando mais tecnicamente, ele casa com
uma posição onde se tenha um caractere que possa fazer parte de uma palavra e um caractere que não possa fazer
parte de uma palavra, um ao lado do outro, não importa qual venha primeiro.
Pra resolver o problema de achar apenas a palavra "por", poderíamos usar a expressão \bpor\b
. Para
achar todas as palavras que comecem com caracteres quaisquer, por exemplo, se, basta colocar o
\b
antes deles: \bse
(casa com será, senhor e a própria palavra
se).
Se você quiser achar todas as palavras que terminam com um determinado texto, por exemplo, de, é só colocar
o \b
após o texto: de\b
(casa com honestidade, simplicidade, idade
e a palavra de).
O \B
nega o \b
, ou seja, casa com tudo aquilo que ele não casa. Então, o \B
casa quando não se tem um início ou fim de uma palavra. Ex: \Bdor\b
(casa com
limpador, corredor, mas não com dor).
É importante deixar claro que não é feita nenhuma análise linguística para determinar se uma porção de texto é realmente uma palavra; dessa forma, P4ew1C é considerada uma palavra porque todos os seus caracteres podem fazer parte de palavras (letras e dígitos).
Caracteres especiais
Se você tiver na sua string a palavra porém e a expressão regular \bpor\b
, a expressão casa
com o por do porém. Isso é um problema, porque com essa expressão regular, estamos deixando claro
que só queremos casar com a palavra por. Por que então isso acontece? Por causa da letra é do
porém. Trata-se de uma letra com acento, e letras desse tipo não são reconhecidas como caracteres que
podem fazer parte de uma palavra na engine que estamos usando e nem em algumas outras.
No caso, a engine encontra um caractere que pode fazer parte de uma palavra (r), ao lado de um que não pode fazer parte de uma palavra(é), e entende equivocadamente que ele encontrou a palavra por.
Como resolver esse problema? Uma solução é usar lookarounds. Um lookahead, que é um tipo de
lookaround, pode ser usado no lugar do segundo \b
: (?=[^À-ÿA-z0-9_])
.
Lookarounds não serão explicados em detalhes aqui, porque eles são explicados em outro
tutorial. Por enquanto, você precisa apenas saber que esse lookahead verifica se o próximo caractere não é uma
letra, nem um dígito e nem um underline.
É necessário também um lookbehind no lugar do primeiro \b
. A única diferença para o lookahead é a
colocação de um <
após o ?
. O lookbehind olha para o caractere que está antes do
p do por e faz a mesma verificação do lookahead. Assim, a expressão regular completa fica assim:
(?<=[^À-ÿA-z0-9_])por(?=[^À-ÿA-z0-9_])>
.
Lembrando que o exemplo anterior pressupõe que há pelo menos um caractere antes e após o por. Assim, ela
não casa quando não há caracteres antes e depois dele. Pra casar nessas situações também, é só colocar uma
alternação dentro do lookahead com uma alternativa que casa se estiver no fim da string e uma alternação dentro
do lookbehind com uma alternativa que casa se estiver no início da string:
(?<=[^À-ÿA-z0-9_]|^)por(?=[^À-ÿA-z0-9_]|$)
.
O mesmo problema do \b
também acontece com o \B
. Se mudarmos a expressão regular
\bpor\b
, trocando os \b
por \B
, teremos uma expressão regular que
verifica se temos o trecho por fazendo parte necessariamente de uma palavra maior. Só que, como foi dito,
usando o \B
, nessa engine, não há suporte à letras que são caracteres especiais. A solução é quase
a mesma do \b
. A diferença é que a classe de caracteres não deve ser negada em nenhum dos
lookarounds. Ou seja, é só tirar os ^
dos lookarounds.