Word boundaries

  1. Caracteres especiais

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.