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

Apare espaços à direita com PostgreSQL


Existem muitos personagens invisíveis diferentes. Muitos deles têm a propriedade WSpace=Y ("espaço em branco") em Unicode. Mas alguns caracteres especiais não são considerados "espaços em branco" e ainda não possuem representação visível. Os excelentes artigos da Wikipedia sobre espaço (pontuação) e caracteres de espaço em branco devem dar uma ideia.

O Unicode é péssimo nesse aspecto:introduz muitos caracteres exóticos que servem principalmente para confundir as pessoas.

O padrão SQL trim() a função por padrão apenas apara o caractere de espaço latino básico (Unicode:U+0020 / ASCII 32). O mesmo com o rtrim() e ltrim() variantes. Sua chamada também visa apenas esse personagem em particular.

Use expressões regulares com regexp_replace() em vez de.

À direita


Para remover todos os espaços em branco à direita (mas não espaço em branco dentro a corda):
SELECT regexp_replace(eventdate, '\s+$', '') FROM eventdates;

A expressão regular explicada:
\s ... abreviação de classe de expressão regular para [[:space:]]
    - que é o conjunto de caracteres de espaço em branco - veja as limitações abaixo
+ ... 1 ou mais correspondências consecutivas
$ ... fim da corda

Demonstração:
SELECT regexp_replace('inner white   ', '\s+$', '') || '|'

Devoluções:
inner white|

Sim, é um único barra invertida (\ ). Detalhes nesta resposta relacionada:
  • SQL seleciona onde a coluna começa com \

Liderando


Para remover todos os espaços em branco à esquerda (mas não espaço em branco dentro da string):
regexp_replace(eventdate, '^\s+', '')

^ .. início da string

Ambos


Para remover ambos , você pode encadear as chamadas de função acima:
regexp_replace(regexp_replace(eventdate, '^\s+', ''), '\s+$', '')

Ou você pode combinar ambos em uma única chamada com duas ramificações .
Adicionar 'g' como 4º parâmetro para substituir todas as correspondências, não apenas a primeira:
regexp_replace(eventdate, '^\s+|\s+$', '', 'g')

Mas isso normalmente deve ser mais rápido com substring() :
substring(eventdate, '\S(?:.*\S)*')

\S ... tudo mas espaço em branco
(?: re ) ... conjunto de parênteses sem captura
.* ... qualquer string de 0-n caracteres

Ou um destes:
substring(eventdate, '^\s*(.*\S)')
substring(eventdate, '(\S.*\S)')  -- only works for 2+ printing characters

( re ) ... Capturando conjunto de parênteses

Efetivamente leva o primeiro caractere sem espaço em branco e tudo até o último caractere sem espaço em branco, se disponível.

Espaço em branco?


Existem mais alguns caracteres relacionados que não são classificados como "espaço em branco" em Unicode - portanto, não estão contidos na classe de caracteres [[:space:]] .

Eles são impressos como glifos invisíveis no pgAdmin para mim:"vogal mongol", "espaço de largura zero", "não-juntor de largura zero", "juntor de largura zero":
SELECT E'\u180e', E'\u200B', E'\u200C', E'\u200D';

'᠎' | '​' | '‌' | '‍'

Mais dois, imprimindo como visível glifos no pgAdmin, mas invisíveis no meu navegador:"word joiner", "espaço sem quebra de largura zero":
SELECT E'\u2060', E'\uFEFF';
'⁠' | ''

Em última análise, se os caracteres são tornados invisíveis ou não, também depende da fonte usada para exibição.

Para remover todos esses também, substitua '\s' com '[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]' ou '[\s᠎​‌‍⁠]' (observe caracteres invisíveis à direita!).
Exemplo, em vez de:
regexp_replace(eventdate, '\s+$', '')

usar:
regexp_replace(eventdate, '[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]+$', '')

ou:
regexp_replace(eventdate, '[\s᠎​‌‍⁠]+$', '')  -- note invisible characters

Limitações


Há também a classe de caracteres Posix [[:graph:]] supostamente para representar "caracteres visíveis". Exemplo:
substring(eventdate, '([[:graph:]].*[[:graph:]])')

Funciona de forma confiável para caracteres ASCII em todas as configurações (onde se resume a [\x21-\x7E] ), mas além disso você atualmente (incl. pág. 10) depende das informações fornecidas pelo sistema operacional subjacente (para definir ctype ) e possivelmente configurações de localidade.

Estritamente falando, esse é o caso de todos referência a uma classe de caracteres, mas parece haver mais desacordo com os menos usados, como graph . Mas você pode ter que adicionar mais caracteres à classe de caracteres [[:space:]] (abreviação \s ) para capturar todos os caracteres de espaço em branco. Como:\u2007 , \u202f e \u00a0 também parecem estar faltando para @XiCoN JFS.

O manual:

Dentro de uma expressão de colchetes, o nome de uma classe de caracteres entre [: e :] representa a lista de todos os caracteres pertencentes a essa classe. Os nomes de classes de caracteres padrão são:alnum , alpha , blank , cntrl ,digit , graph , lower , print , punct , space , upper , xdigit .Eles representam as classes de caracteres definidas em ctype.Uma localidade pode fornecer outras.

Minha ênfase em negrito.

Observe também esta limitação que foi corrigida com o Postgres 10:

Corrige a manipulação de classes de caracteres de expressões regulares para códigos de caracteres grandes, particularmente caracteres Unicode acima de U+7FF (Tom Lane)

Anteriormente, esses caracteres nunca eram reconhecidos como pertencentes a classes de caracteres dependentes de localidade, como [[:alpha:]] .