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

Trim bagerste rum med PostgreSQL

Der er mange forskellige usynlige karakterer. Mange af dem har egenskaben WSpace=Y ("whitespace") i Unicode. Men nogle specialtegn betragtes ikke som "whitespace" og har stadig ingen synlig repræsentation. De fremragende Wikipedia-artikler om mellemrum (tegnsætning) og mellemrumstegn burde give dig en idé.

Unicode stinker i denne henseende:introducerer masser af eksotiske karakterer, der primært tjener til at forvirre folk.

Standard SQL trim() funktion trimmer som standard kun det grundlæggende latinske mellemrum (Unicode:U+0020 / ASCII 32). Det samme med rtrim() og ltrim() varianter. Dit opkald er også kun rettet mod den pågældende karakter.

Brug regulære udtryk med regexp_replace() i stedet.

Tilbage

For at fjerne alt efterfølgende hvidt mellemrum (men ikke hvidt mellemrum indeni strengen):

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

Det regulære udtryk forklarede:
\s ... regulært udtryksklasseforkortning for [[:space:]]
    - som er sættet af mellemrumstegn - se begrænsninger nedenfor
+ ... 1 eller flere på hinanden følgende match
$ ... slutningen af ​​strengen

Demo:

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

Returnerer:

inner white|

Ja, det er en single omvendt skråstreg (\ ). Detaljer i dette relaterede svar:

  • SQL vælg, hvor kolonnen begynder med \

Førende

For at fjerne alt førende hvidt mellemrum (men ikke mellemrum inde i strengen):

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

^ .. start af streng

Begge

For at fjerne begge , kan du sammenkæde ovenstående funktionskald:

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

Eller du kan kombinere begge i et enkelt opkald med to filialer .
Tilføj 'g' som 4. parameter for at erstatte alle matches, ikke kun den første:

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

Men det burde typisk være hurtigere med substring() :

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

\S ... alt men hvidt mellemrum
(?: re ) ... ikke-indfangende sæt parenteser
.* ... enhver streng på 0-n tegn

Eller en af ​​disse:

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

( re ) ... Optager sæt parenteser

Tager effektivt det første tegn uden mellemrum og alt op til det sidste tegn uden mellemrum, hvis det er tilgængeligt.

Whitespace?

Der er et par flere relaterede tegn, som ikke er klassificeret som "whitespace" i Unicode - så ikke indeholdt i tegnklassen [[:space:]] .

Disse udskrives som usynlige glyffer i pgAdmin for mig:"mongolsk vokal", "zero width space", "zero width non-joiner", "zero width joiner":

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

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

To mere, udskriver som synlige glyffer i pgAdmin, men usynlige i min browser:"word joiner", "zero width non-breaking space":

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

I sidste ende afhænger hvorvidt tegn gøres usynlige eller ej, også af den skrifttype, der bruges til visning.

For at fjerne alle disse udskift også '\s' med '[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]' eller '[\s᠎​‌‍⁠]' (bemærk efterfølgende usynlige tegn!).
Eksempel i stedet for:

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

brug:

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

eller:

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

Begrænsninger

Der er også Posix-tegnklassen [[:graph:]] formodes at repræsentere "synlige tegn". Eksempel:

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

Det fungerer pålideligt for ASCII-tegn i enhver opsætning (hvor det koger ned til [\x21-\x7E] ), men derudover er du i øjeblikket (inkl. s. 10) afhængig af information fra det underliggende OS (for at definere ctype ) og muligvis lokalitetsindstillinger.

Strengt taget er det tilfældet for alle henvisning til en karakterklasse, men der ser ud til at være mere uenighed med de mindre almindeligt brugte som graf . Men du skal muligvis tilføje flere tegn til tegnklassen [[:space:]] (stenografi \s ) for at fange alle mellemrumstegn. Ligesom:\u2007 , \u202f og \u00a0 synes også at mangle for @XiCoN JFS.

Manualen:

Inden for et parentes udtryk, navnet på en karakterklasse indesluttet i[: og :] står for listen over alle karakterer, der tilhører den klasse. Standard karakterklassenavne er:alnum , alpha , blank , cntrl ,digit , graph , lower , print , punct , space , upper , xdigit .Disse står for tegnklasserne defineret i ctype. En lokalitet kan give andre.

Fed fremhævelse mine.

Bemærk også denne begrænsning, der blev rettet med Postgres 10:

Ret regulære udtryks karakterklassehåndtering for store tegnkoder, især Unicode-tegn over U+7FF (Tom Lane)

Tidligere blev sådanne tegn aldrig genkendt som tilhørende lokalitetsafhængige karakterklasser såsom [[:alpha:]] .



  1. Sådan ser du forespørgselshistorik i SQL Server Management Studio

  2. Brug af bindevariable med dynamisk SELECT INTO-sætning i PL/SQL

  3. Hvordan indlæses et stort antal strenge for at matche med Oracle-databasen?

  4. Hvad er forskellen mellem ROWNUM og ROW_NUMBER i en Oracle-database?