使用PostgreSQL修剪尾随空格

问题描述 投票:31回答:4

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

SELECT TRIM(both ' ' from eventDate) 
FROM EventDates;

然而,尾随空间不会消失。此外,当我尝试修剪日期中的另一个字符(例如数字)时,它也不会修剪。如果我正确地阅读the manual这应该工作。有什么想法吗?

sql postgresql whitespace trim removing-whitespace
4个回答
61
投票

有许多不同的隐形字符。他们中的许多人都拥有Unicode中的属性WSpace=Y(“whitespace”)。但是一些特殊字符不被视为“空白”,仍然没有可见的表示。关于space (punctuation)whitespace characters的优秀维基百科文章应该会给你一个想法。

<rant> Unicode在这方面很糟糕:引入了很多充满异国情调的角色,主要是为了让人迷惑。</ rant>

默认情况下,The standard SQL trim() function仅修剪基本的拉丁空格字符(Unicode:U + 0020 / ASCII 32)。与rtrim() and ltrim()变体相同。您的通话也只针对该特定角色。

使用regexp_replace()的正则表达式。

Trailing

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

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

正则表达式解释说: \s .. regular expression class shorthand for [[:space:]] - 这是一组空白字符 - 请参阅下面的限制 + ..连续1场或更多场比赛 $ ..字符串的结尾

演示:

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

返回:

inner white|

是的,这是一个反斜杠(\)。这个相关答案的细节。

Leading

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

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

^ ..字符串的开头

Both

要删除这两个,您可以链接上面的函数调用:

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

或者你可以用两个branches将它们组合在一起。 添加'g'作为第4个参数来替换所有匹配,而不仅仅是第一个:

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

但是使用substring()通常应该更快:

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

\S ..除了空白之外的一切 (?:re) Non-capturing set of parentheses .* ..任何0-n字符串

或者其中一个:

substring(eventdate, '^\s*(.*\S)')
substring(eventdate, '(\S.*\S)')

(re) .. Capturing set of parentheses

有效地获取第一个非空白字符以及最后一个非空白字符(如果可用)。

空白?

还有一些related characters which are not classified as "whitespace" in Unicode - 所以不包含在字符类[[:space:]]中。

这些在pgAdmin中打印为隐形字形,对我来说:“mongolian元音”,“零宽度空间”,“零宽度非连接”,“零宽度连接”:

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

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

另外两个,在pgAdmin中打印为可见字形,但在我的浏览器中不可见:“word joiner”,“零宽度不间断空格”:

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

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

要删除所有这些,请将'\s'替换为'[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]''[\s᠎​‌‍⁠]'(注意尾随隐形字符!)。 示例,而不是:

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

使用:

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

要么:

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

Limitations

还有Posix character class [[:graph:]]应该代表“可见的角色”。例:

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

它适用于每个设置中的ASCII字符(归结为[\x21-\x7E]),但除此之外,您目前(包括第10页)依赖于底层操作系统(定义ctype)和可能的区域设置提供的信息。

严格地说,对于每个对字符类的引用都是这种情况,但是对于像图这样不常用的引用似乎更加不一致。但是你可能需要在字符类[[:space:]](简写\s)中添加更多字符来捕获所有空格字符。 Like: \u2007, \u202f and \u00a0 seem to also be missing for @XiCoN JFS

The manual:

在括号表达式中,[::]中包含的字符类的名称代表属于该类的所有字符的列表。标准字符类名称是:alnumalphablankcntrldigitgraphlowerprintpunctspaceupperxdigit。这些代表ctype中定义的字符类。区域设置可以提供其他人。

大胆强调我的。

还要注意这个限制是fixed with Postgres 10

修复正则表达式对大字符代码的字符类处理,特别是U+7FF上的Unicode字符(Tom Lane)

以前,这些字符从未被识别为属于依赖于语言环境的字符类,例如[[:alpha:]]


2
投票

它应该按照你处理它的方式工作,但是如果不知道具体的字符串就很难说。

如果您只是修剪前导空格,您可能希望使用更简洁的形式:

SELECT RTRIM(eventDate) 
FROM EventDates;

这是一个little test向您展示它的工作原理。告诉我们它是否成功!


2
投票

如果你的空格不仅仅是space元值,那么你需要使用regexp_replace

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

在上面的例子中,我绑定了()中的返回值,这样你就可以很容易地看到正则表达式替换在psql提示符下工作。因此,您需要删除代码中的内容。


0
投票
SELECT  replace(('       devo    system      ') ,' ','');

它给出:devosystem

© www.soinside.com 2019 - 2024. All rights reserved.