PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Função Escape para expressão regular ou padrões LIKE


Para responder à pergunta no topo:

Função de escape de expressão regular


Vamos começar com uma lista completa de caracteres com significado especial em expressão regular padrões:
!$()*+.:<=>?[\]^{|}-

Envolvidos em uma expressão de colchetes, a maioria deles perde seu significado especial - com algumas exceções:
  • - precisa ser o primeiro ou o último ou significa um intervalo de caracteres.
  • ] e \ tem que ser escapado com \ (na substituição também).

Depois de adicionar parênteses de captura para a referência de retorno abaixo, obtemos este padrão regexp:
([!$()*+.:<=>?[\\\]^{|}-])

Ao usá-lo, esta função escapa todos os caracteres especiais com uma barra invertida (\ ) - removendo assim o significado especial:
CREATE OR REPLACE FUNCTION f_regexp_escape(text)
  RETURNS text
  LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
$func$
SELECT regexp_replace($1, '([!$()*+.:<=>?[\\\]^{|}-])', '\\\1', 'g')
$func$;

Adicionar PARALLEL SAFE (porque é ) no Postgres 10 ou posterior para permitir o paralelismo para consultas que o utilizam.

Demonstração

SELECT f_regexp_escape('test(1) > Foo*');

Devoluções:
test\(1\) \> Foo\*

E enquanto:
SELECT 'test(1) > Foo*' ~ 'test(1) > Foo*';

retorna FALSE , o que pode ser uma surpresa para usuários ingênuos,
SELECT 'test(1) > Foo*' ~ f_regexp_escape('test(1) > Foo*');

Retorna TRUE como deveria agora.

LIKE função de escape


Para completar, o pingente para LIKE padrões, onde apenas três caracteres são especiais:
\%_

O manual:

O caractere de escape padrão é a barra invertida, mas um diferente pode ser selecionado usando o ESCAPE cláusula.

Esta função assume o padrão:
CREATE OR REPLACE FUNCTION f_like_escape(text)
  RETURNS text
  LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
$func$
SELECT replace(replace(replace($1
         , '\', '\\')  -- must come 1st
         , '%', '\%')
         , '_', '\_');
$func$;

Poderíamos usar o mais elegante regexp_replace() aqui também, mas para os poucos caracteres, uma cascata de replace() funções é mais rápido.

Novamente, PARALLEL SAFE no Postgres 10 ou posterior.

Demonstração

SELECT f_like_escape('20% \ 50% low_prices');

Devoluções:
20\% \\ 50\% low\_prices