sql >> Database >  >> RDS >> PostgreSQL

Achterliggende spaties bijsnijden met PostgreSQL

Er zijn veel verschillende onzichtbare karakters. Velen van hen hebben de eigenschap WSpace=Y ("witruimte") in Unicode. Maar sommige speciale tekens worden niet als "witruimte" beschouwd en hebben nog steeds geen zichtbare weergave. De uitstekende Wikipedia-artikelen over spatie (interpunctie) en witruimtetekens zouden u een idee moeten geven.

Unicode is in dit opzicht waardeloos:het introduceren van veel exotische karakters die vooral dienen om mensen in verwarring te brengen.

De standaard SQL trim() functie trimt standaard alleen het Latijnse spatieteken (Unicode:U+0020 / ASCII 32). Hetzelfde met de rtrim() en ltrim() varianten. Je oproep is ook alleen gericht op dat specifieke personage.

Gebruik reguliere expressies met regexp_replace() in plaats daarvan.

Trailing

Om alle achterliggende witruimte te verwijderen (maar geen witruimte binnen de string):

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

De reguliere expressie uitgelegd:
\s ... reguliere expressieklasse steno voor [[:space:]]
    - dit is de set witruimtetekens - zie beperkingen hieronder
+ ... 1 of meer opeenvolgende wedstrijden
$ ... einde van string

Demo:

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

Retourneren:

inner white|

Ja, dat is een enkele backslash (\ ). Details in dit gerelateerde antwoord:

  • SQL selecteer waar de kolom begint met \

Toonaangevend

Om alle voorlopende witruimte te verwijderen (maar geen witruimte binnen de string):

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

^ .. begin van string

Beide

Om beide te verwijderen , kunt u bovenstaande functieaanroepen koppelen:

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

Of u kunt beide combineren in één gesprek met twee filialen .
Voeg 'g' als 4e parameter om alle overeenkomsten te vervangen, niet alleen de eerste:

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

Maar dat zou normaal gesproken sneller moeten zijn met substring() :

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

\S ... alles maar witruimte
(?: re ) ... niet-vastleggende set haakjes
.* ... een willekeurige reeks van 0-n tekens

Of een van deze:

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

( re ) ... Set haakjes vastleggen

Neemt effectief het eerste teken zonder witruimte en alles tot het laatste teken zonder witruimte, indien beschikbaar.

Witruimte?

Er zijn nog een paar verwante karakters die niet zijn geclassificeerd als "witruimte" in Unicode - dus niet opgenomen in de tekenklasse [[:space:]] .

Deze worden voor mij afgedrukt als onzichtbare glyphs in pgAdmin:"mongoolse klinker", "zero width space", "zero width non-joiner", "zero width joiner":

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

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

Nog twee, afdrukken als zichtbaar glyphs in pgAdmin, maar onzichtbaar in mijn browser:"word joiner", "zero width non-breaking space":

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

Of tekens al dan niet onzichtbaar worden gemaakt, hangt uiteindelijk ook af van het lettertype dat voor de weergave wordt gebruikt.

Om al deze te verwijderen vervang ook '\s' met '[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]' of '[\s᠎​‌‍⁠]' (let op onzichtbare tekens!).
Voorbeeld, in plaats van:

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

gebruik:

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

of:

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

Beperkingen

Er is ook de Posix-tekenklasse [[:graph:]] verondersteld om "zichtbare tekens" te vertegenwoordigen. Voorbeeld:

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

Het werkt betrouwbaar voor ASCII-tekens in elke configuratie (waar het neerkomt op [\x21-\x7E] ), maar daarnaast bent u momenteel (incl. pg 10) afhankelijk van informatie die wordt geleverd door het onderliggende besturingssysteem (om ctype te definiëren ) en mogelijk landinstellingen.

Strikt genomen is dat het geval voor elke verwijzing naar een tekenklasse, maar er lijkt meer onenigheid te zijn met de minder vaak gebruikte, zoals graph . Maar het kan zijn dat u meer tekens moet toevoegen aan de tekenklasse [[:space:]] (afgekort \s ) om alle witruimtetekens te vangen. Zoals:\u2007 , \u202f en \u00a0 lijken ook te ontbreken voor @XiCoN JFS.

De handleiding:

Binnen een uitdrukking tussen haakjes, de naam van een tekenklasse tussen[: en :] staat voor de lijst van alle karakters die tot die klasse behoren. Standaardtekenklassenamen zijn:alnum , alpha , blank , cntrl ,digit , graph , lower , print , punct , space , upper , xdigit .Deze staan ​​voor de tekenklassen gedefinieerd in ctype.Een landinstelling kan andere leveren.

Vetgedrukte nadruk van mij.

Let ook op deze beperking die is opgelost met Postgres 10:

Repareer de tekenklasse-afhandeling van reguliere expressies voor grote tekencodes, met name Unicode-tekens boven U+7FF (Tom Lane)

Voorheen werden dergelijke karakters nooit herkend als behorend tot locale-afhankelijke karakterklassen zoals [[:alpha:]] .



  1. Fout bij gebruik van patroonovereenkomst die niet lijkt op die in PostgreSQL

  2. Hoe de standaard nls_date_format voor de Oracle jdbc-client te wijzigen

  3. Gegevens uit database weergeven met basisadapter en lijstweergave

  4. MariaDB JSON_ARRAY() uitgelegd