关于sql:PostgreSQL的Trim尾随空格

Trim trailing spaces with PostgreSQL

我有一个列eventDate,其中包含尾随空格。我正在尝试使用PostgreSQL函数TRIM()删除它们。更具体地说,我正在运行:

1
2
SELECT TRIM(BOTH ' ' FROM eventDate)
FROM EventDates;

但是,尾随空格不会消失。此外,当我尝试从日期中修剪另一个字符(例如数字)时,它也不会修剪。如果我正确阅读了手册,则应该可以使用。有什么想法吗?


有许多不同的不可见字符。他们中的许多人在Unicode中都具有属性WSpace=Y("空白")。但是某些特殊字符不被视为"空白",并且仍然没有可见的表示形式。 Wikipedia上有关空格(标点)和空白字符的出色文章应该可以使您有所了解。

Unicode在这方面很烂:引入了许多主要用来使人们感到困惑的奇特字符。

默认情况下,标准SQL trim()函数仅修剪基本的拉丁空格字符(Unicode:U 0020 / ASCII 32)。与rtrim()ltrim()变体相同。您的通话也仅针对该特定字符。

使用正则表达式和regexp_replace()代替。

尾随

要删除所有结尾的空格(但不能删除字符串中的空格):

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

正则表达式说明:
\\s .. [[:space:]]的正则表达式类的简写
-这是一组空白字符-请参阅下面的限制
+ .. 1个或多个连续匹配
$ ..字符串结尾

演示:

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

返回:

1
INNER white|

是的,那是一个反斜杠(\\)。此相关答案中的详细信息。

  • SQL选择列以\\\\开头的位置

领导

要删除所有前导空格(但不能删除字符串中的空格):

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

^ ..字符串的开头

要同时删除这两个函数,可以链接以上函数调用:

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

或者您可以在一个呼叫中将其与两个分支结合在一起。
添加'g'作为第四个参数以替换所有匹配项,而不仅仅是第一个:

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

但是使用substring()

通常应该更快

1
SUBSTRING(eventdate, '\\S(?:.*\\S)*')

\\s ..除空白外的所有内容
(?: re )非捕获括号
.* .. 0-n个字符的任何字符串

或以下之一:

1
2
SUBSTRING(eventdate, '^\\s*(.*\\S)')
SUBSTRING(eventdate, '(\\S.*\\S)')

( re ) ..捕获一组括号

有效地获取第一个非空白字符,如果可能的话,将取所有内容直至最后一个非空白字符。

空格?

还有一些其他相关字符在Unicode中未被归类为"空白",因此不包含在字符类[[:space:]]中。

对于我来说,这些打印为pgAdmin中的不可见字形:"蒙古语元音","零宽度空格","零宽度非连接符","零宽度连接符":

1
2
3
SELECT E'\\u180e', E'\\u200B', E'\\u200C', E'\\u200D';

'á?' | 'a€?' | 'a€?' | 'a€?'

还有两个,在pgAdmin中打印为可见的字形,但在我的浏览器中不可见:"单词连接器","零宽度不间断空格":

1
2
SELECT E'\\u2060', E'\\uFEFF';
'a?' | ''

最终,是否使字符不可见还取决于用于显示的字体。

也要删除所有这些内容,请将'\\s'替换为'[\\s\\u180e\\u200B\\u200C\\u200D\\u2060\\uFEFF]''[\\sá?a€?a€?a€?a?]'(注意结尾的不可见字符!)。
示例,而不是:

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

使用:

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

或:

1
regexp_replace(eventdate, '[\\sá?a€?a€?a€?a?]+$', '')  -- note invisible characters

局限性

还有Posix字符类[[:graph:]]应该表示"可见字符"。示例:

1
SUBSTRING(eventdate, '([[:graph:]].*[[:graph:]])')

它在每种设置中都可以可靠地用于ASCII字符(归结为[\\x21-\\x7E]),但目前为止(包括第10页)取决于基础操作系统提供的信息(定义ctype),并且可能是语言环境设置。

严格来说,对字符类的每次引用都是这种情况,但似乎与图形等较不常用的字符存在更多的分歧。但是您可能必须向字符类[[:space:]](速记\\s)添加更多字符才能捕获所有空白字符。像:@xiCoN JFS似乎也缺少\\u2007\\u202f\\u00a0

手册:

Within a bracket expression, the name of a character class enclosed in
[: and :] stands for the list of all characters belonging to that
class. Standard character class names are: alnum, alpha, blank, cntrl,
digit, graph, lower, print, punct, space, upper, xdigit.
These stand for the character classes defined in ctype.
A locale can provide others.

强调粗体的人。

还请注意此限制已在Postgres 10中修复:

Fix regular expressions' character class handling for large character
codes, particularly Unicode characters above U+7FF (Tom Lane)

Previously, such characters were never recognized as belonging to
locale-dependent character classes such as [[:alpha:]].


它应该以您处理它的方式工作,但是在不知道特定字符串的情况下很难说。

如果仅修剪前导空格,则可能要使用更简洁的形式:

1
2
SELECT RTRIM(eventDate)
FROM EventDates;

这是一个向您展示它是否有效的小测试。
告诉我们是否可行!


如果您的空格不只是space元值,则需要使用regexp_replace

1
2
 SELECT '(' || REGEXP_REPLACE(eventDate, E'[[:space:]]', '', 'g') || ')'
 FROM EventDates;

在上面的示例中,我将返回值限制在()中,以便您可以轻松地看到regex replace在psql提示符中起作用。因此,您需要删除代码中的那些内容。


1
SELECT  REPLACE(('       devo    system      ') ,' ','');

它给出:devosystem