sql >> Base de Datos >  >> RDS >> PostgreSQL

Recorte los espacios finales con PostgreSQL

Hay muchos personajes invisibles diferentes. Muchos de ellos tienen la propiedad WSpace=Y ("espacio en blanco") en Unicode. Pero algunos caracteres especiales no se consideran "espacios en blanco" y aún no tienen una representación visible. Los excelentes artículos de Wikipedia sobre espacios (puntuación) y espacios en blanco deberían darle una idea.

Unicode apesta en este sentido:presenta muchos caracteres exóticos que sirven principalmente para confundir a la gente.

El SQL estándar trim() La función por defecto solo recorta el carácter de espacio latino básico (Unicode:U+0020 / ASCII 32). Lo mismo con rtrim() y ltrim() variantes. Tu llamada también solo se dirige a ese personaje en particular.

Usa expresiones regulares con regexp_replace() en su lugar.

Siguiente

Para eliminar todos los espacios en blanco finales (pero no espacios en blanco dentro la cadena):

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

La expresión regular explicada:
\s ... abreviatura de clase de expresión regular para [[:space:]]
    - que es el conjunto de caracteres de espacio en blanco - consulte las limitaciones a continuación
+ ... 1 o más coincidencias consecutivas
$ ... final de la cadena

Demostración:

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

Devoluciones:

inner white|

Sí, eso es un single barra invertida (\ ). Detalles en esta respuesta relacionada:

  • Selección de SQL donde la columna comienza con \

Liderar

Para eliminar todos los espacios en blanco iniciales (pero no espacios en blanco dentro de la cadena):

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

^ .. inicio de cadena

Ambos

Para eliminar ambos , puede encadenar llamadas a funciones anteriores:

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

O puede combinar ambos en una sola llamada con dos sucursales .
Añadir 'g' como cuarto parámetro para reemplazar todas las coincidencias, no solo la primera:

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

Pero eso normalmente debería ser más rápido con substring() :

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

\S ... todo pero espacio en blanco
(?: re ) ... conjunto de paréntesis que no capturan
.* ... cualquier cadena de 0-n caracteres

O uno de estos:

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

( re ) ... Capturando conjunto de paréntesis

Toma efectivamente el primer carácter que no sea un espacio en blanco y todo hasta el último carácter que no sea un espacio en blanco, si está disponible.

¿Espacio en blanco?

Hay algunos caracteres más relacionados que no están clasificados como "espacios en blanco" en Unicode, por lo que no están incluidos en la clase de caracteres [[:space:]] .

Estos se imprimen como glifos invisibles en pgAdmin para mí:"vocal mongol", "espacio de ancho cero", "no ensamblador de ancho cero", "unidor de ancho cero":

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

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

Dos más, imprimiendo como visible glifos en pgAdmin, pero invisibles en mi navegador:"unión de palabras", "espacio de ancho cero sin separación":

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

En última instancia, si los caracteres se vuelven invisibles o no, también depende de la fuente utilizada para la visualización.

Para eliminar todos estos también, reemplace '\s' con '[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]' o '[\s᠎​‌‍⁠]' (¡tenga en cuenta los caracteres invisibles al final!).
Ejemplo, en lugar de:

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

usar:

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

o:

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

Limitaciones

También existe la clase de caracteres Posix [[:graph:]] se supone que representan "caracteres visibles". Ejemplo:

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

Funciona de manera confiable para caracteres ASCII en cada configuración (donde se reduce a [\x21-\x7E] ), pero más allá de eso actualmente (incl. pág. 10) depende de la información proporcionada por el sistema operativo subyacente (para definir ctype ) y posiblemente la configuración regional.

Estrictamente hablando, ese es el caso de todas referencia a una clase de carácter, pero parece haber más desacuerdo con las menos utilizadas como graph . Pero es posible que deba agregar más caracteres a la clase de caracteres [[:space:]] (abreviatura \s ) para capturar todos los caracteres de espacio en blanco. Me gusta:\u2007 , \u202f y \u00a0 parece que también falta para @XiCoN JFS.

El manual:

Dentro de una expresión de paréntesis, el nombre de una clase de carácter encerrada entre [: y :] representa la lista de todos los caracteres que pertenecen a esa clase. Los nombres de clases de caracteres estándar son:alnum , alpha , blank , cntrl ,digit , graph , lower , print , punct , space , upper , xdigit .Estos representan las clases de caracteres definidas en ctype. Una configuración regional puede proporcionar otras.

Énfasis en negrita mío.

También tenga en cuenta esta limitación que se corrigió con Postgres 10:

Corrija el manejo de clases de caracteres de expresiones regulares para códigos de caracteres grandes, particularmente caracteres Unicode por encima de U+7FF (Tom Lane)

Anteriormente, dichos caracteres nunca se reconocían como pertenecientes a clases de caracteres dependientes de la configuración regional, como [[:alpha:]] .