我有一个包含尾随空格的eventDate
列。我试图用PostgreSQL函数TRIM()
删除它们。更具体地说,我正在运行:
SELECT TRIM(both ' ' from eventDate)
FROM EventDates;
然而,尾随空间不会消失。此外,当我尝试修剪日期中的另一个字符(例如数字)时,它也不会修剪。如果我正确地阅读the manual这应该工作。有什么想法吗?
有许多不同的隐形字符。他们中的许多人都拥有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()
的正则表达式。
要删除所有尾随空格(但不是字符串中的空格):
SELECT regexp_replace(eventdate, '\s+$', '') FROM eventdates;
正则表达式解释说:
\s
.. regular expression class shorthand for [[:space:]]
- 这是一组空白字符 - 请参阅下面的限制
+
..连续1场或更多场比赛
$
..字符串的结尾
演示:
SELECT regexp_replace('inner white ', '\s+$', '') || '|'
返回:
inner white|
是的,这是一个反斜杠(\
)。这个相关答案的细节。
要删除所有前导空格(但不是字符串中的空格):
regexp_replace(eventdate, '^\s+', '')
^
..字符串的开头
要删除这两个,您可以链接上面的函数调用:
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
还有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。
在括号表达式中,
[:
和:]
中包含的字符类的名称代表属于该类的所有字符的列表。标准字符类名称是:alnum
,alpha
,blank
,cntrl
,digit
,graph
,lower
,punct
,space
,upper
,xdigit
。这些代表ctype中定义的字符类。区域设置可以提供其他人。
大胆强调我的。
还要注意这个限制是fixed with Postgres 10:
修复正则表达式对大字符代码的字符类处理,特别是
U+7FF
上的Unicode字符(Tom Lane)以前,这些字符从未被识别为属于依赖于语言环境的字符类,例如
[[:alpha:]]
。
它应该按照你处理它的方式工作,但是如果不知道具体的字符串就很难说。
如果您只是修剪前导空格,您可能希望使用更简洁的形式:
SELECT RTRIM(eventDate)
FROM EventDates;
这是一个little test向您展示它的工作原理。告诉我们它是否成功!
如果你的空格不仅仅是space
元值,那么你需要使用regexp_replace
:
SELECT '(' || REGEXP_REPLACE(eventDate, E'[[:space:]]', '', 'g') || ')'
FROM EventDates;
在上面的例子中,我绑定了(
和)
中的返回值,这样你就可以很容易地看到正则表达式替换在psql提示符下工作。因此,您需要删除代码中的内容。
SELECT replace((' devo system ') ,' ','');
它给出:devosystem