PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Taglia gli spazi finali con PostgreSQL

Ci sono molti personaggi invisibili diversi. Molti di loro hanno la proprietà WSpace=Y ("spazio bianco") in Unicode. Ma alcuni caratteri speciali non sono considerati "spazi bianchi" e non hanno ancora una rappresentazione visibile. Gli eccellenti articoli di Wikipedia sullo spazio (punteggiatura) e sui caratteri degli spazi bianchi dovrebbero darti un'idea.

Unicode fa schifo in questo senso:introduce molti caratteri esotici che servono principalmente a confondere le persone.

Lo standard SQL trim() per impostazione predefinita, la funzione taglia solo il carattere di spazio latino di base (Unicode:U+0020 / ASCII 32). Lo stesso vale per rtrim() e ltrim() varianti. La tua chiamata prende di mira solo quel particolare personaggio.

Usa le espressioni regolari con regexp_replace() invece.

In coda

Per rimuovere tutti gli spazi bianchi finali (ma non lo spazio bianco dentro la stringa):

SELECT regexp_replace(eventdate, '\s+$', '') FROM eventdates;

Spiegazione dell'espressione regolare:
\s ... scorciatoia di classi di espressioni regolari per [[:space:]]
    - che è l'insieme di spazi bianchi - vedi le limitazioni di seguito
+ ... 1 o più corrispondenze consecutive
$ ... fine della stringa

Demo:

SELECT regexp_replace('inner white   ', '\s+$', '') || '|'

Resi:

inner white|

Sì, è un single barra rovesciata (\ ). Dettagli in questa risposta correlata:

  • SQL seleziona dove la colonna inizia con \

In testa

Per rimuovere tutti gli spazi bianchi iniziali (ma non spazio bianco all'interno della stringa):

regexp_replace(eventdate, '^\s+', '')

^ .. inizio della stringa

Entrambi

Per rimuovere entrambi , puoi concatenare sopra le chiamate di funzione:

regexp_replace(regexp_replace(eventdate, '^\s+', ''), '\s+$', '')

Oppure puoi combinare entrambi in un'unica chiamata con due rami .
Aggiungi 'g' come 4° parametro per sostituire tutte le corrispondenze, non solo la prima:

regexp_replace(eventdate, '^\s+|\s+$', '', 'g')

Ma in genere dovrebbe essere più veloce con substring() :

substring(eventdate, '\S(?:.*\S)*')

\S ... tutto ma spazio bianco
(?: re ) ... insieme di parentesi non catturabili
.* ... qualsiasi stringa di 0-n caratteri

O uno di questi:

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

( re ) ... Cattura set di parentesi

Prende effettivamente il primo carattere non di spazi bianchi e tutto fino all'ultimo carattere non di spazi vuoti, se disponibile.

Spazi bianchi?

Ci sono alcuni altri caratteri correlati che non sono classificati come "spazi bianchi" in Unicode, quindi non sono contenuti nella classe di caratteri [[:space:]] .

Questi vengono stampati come glifi invisibili in pgAdmin per me:"vocale mongola", "spazio larghezza zero", "larghezza zero non joiner", "joiner larghezza zero":

SELECT E'\u180e', E'\u200B', E'\u200C', E'\u200D';

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

Altri due, stampati come visibili glifi in pgAdmin, ma invisibili nel mio browser:"word joiner", "spazio unificatore di larghezza zero":

SELECT E'\u2060', E'\uFEFF';
'⁠' | ''

In definitiva, se i caratteri vengono resi invisibili o meno dipende anche dal carattere utilizzato per la visualizzazione.

Per rimuovere tutti questi sostituisci anche '\s' con '[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]' o '[\s᠎​‌‍⁠]' (nota i caratteri invisibili finali!).
Esempio, invece di:

regexp_replace(eventdate, '\s+$', '')

usa:

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

oppure:

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

Limiti

Esiste anche la classe di caratteri Posix [[:graph:]] dovrebbe rappresentare "caratteri visibili". Esempio:

substring(eventdate, '([[:graph:]].*[[:graph:]])')

Funziona in modo affidabile per i caratteri ASCII in ogni configurazione (dove si riduce a [\x21-\x7E] ), ma oltre a ciò attualmente (incl. pg 10) dipendi dalle informazioni fornite dal sistema operativo sottostante (per definire ctype ) ed eventualmente le impostazioni locali.

A rigor di termini, questo è il caso di tutti riferimento a una classe di caratteri, ma sembra esserci più disaccordo con quelle meno comunemente usate come graph . Ma potresti dover aggiungere più caratteri alla classe di caratteri [[:space:]] (abbreviazione \s ) per catturare tutti gli spazi bianchi. Come:\u2007 , \u202f e \u00a0 sembrano mancare anche per @XiCoN JFS.

Il manuale:

All'interno di un'espressione tra parentesi, il nome di una classe di caratteri racchiusa tra [: e :] sta per l'elenco di tutti i caratteri appartenenti a quella classe. I nomi delle classi di caratteri standard sono:alnum , alpha , blank , cntrl ,digit , graph , lower , print , punct , space , upper , xdigit .Questi rappresentano le classi di caratteri definite in ctype.Un locale può fornirne altri.

Enfasi in grassetto la mia.

Nota anche questa limitazione che è stata corretta con Postgres 10:

Risolto il problema con la gestione delle classi di caratteri delle espressioni regolari per codici carattere di grandi dimensioni, in particolare caratteri Unicode sopra U+7FF (Tom Lane)

In precedenza, tali caratteri non venivano mai riconosciuti come appartenenti a classi di caratteri dipendenti dalle impostazioni locali come [[:alpha:]] .