正则表达式从 postgresql 中的时间戳字符串中间删除“-”

Posted

技术标签:

【中文标题】正则表达式从 postgresql 中的时间戳字符串中间删除“-”【英文标题】:Regex to remove "-" from the middle of a timestamp string in postgresql 【发布时间】:2014-12-09 15:16:54 【问题描述】:

我有一个表格,其中包含 hour 列的 timestamp 格式不正确:

        hour         
---------------------
 2014-12-06-01:44:35
 2014-12-06-01:44:35
 2014-12-06-01:44:35
 2014-12-06-01:44:35
 2014-12-06-01:44:35
 2014-12-06-01:44:35

我想在中间用' '替换-,所以它看起来像这样:

        hour         
---------------------
 2014-12-06 01:44:35
 2014-12-06 01:44:35
 2014-12-06 01:44:35
 2014-12-06 01:44:35
 2014-12-06 01:44:35
 2014-12-06 01:44:35

我试过了:

select regexp_replace(hour, '\d4-\d2-\d2(-)\d2:\d2:\d2', ' ')
from my_table;

但不幸的是,它没有任何区别。 我使用的是 Redshift,而不是 PostgreSQL。

【问题讨论】:

【参考方案1】:

在 postgresql 中创建 Regex 表达式时需要考虑一些事项。首先,您需要转义反斜杠。所以你需要\\,而不是\。其次,您可以通过使用 \n 在括号中捕获第 n 个组来引用捕获组。您可以在替换值中使用捕获组来引用原始字符串的部分内容。

将所有这些放在一起,这就是您所需要的:

regexp_replace('hour', '(\\d4-\\d2-\\d2)-(\\d2:\\d2:\\d2)', '\\1 \\2') 

【讨论】:

【参考方案2】:

Redshift 中的有限选项

regexp_replace(hour, '(^\\d4-\\d2-\\d2)-(\\d2:\\d2:\\d2$)', '\\1 \\2') AS a
regexp_replace(hour, '(^\\d4-\\d\\d-\\d\\d)-(\\d\\d:\\d\\d:\\d\\d)$', '\\1 \\2') AS b
regexp_replace(hour, '(^[\\d-]10)-([\\d:]+)$', '\\1 \\2')                        AS c
left(hour,10) || ' ' ||  substring(hour FROM 12)                           AS e

现代 Postgres (9.1+) 中的更多选项

regexp_replace(hour, '(^\d4-\d2-\d2)-(\d2:\d2:\d2$)', '\1 \2') AS a
regexp_replace(hour, '(^\d4-\d\d-\d\d)-(\d\d:\d\d:\d\d)$', '\1 \2')      AS b
regexp_replace(hour, '(^[\d-]10)-([\d:]+)$', '\1 \2')                    AS c
reverse(regexp_replace(reverse(hour), '-', ' '))                           AS d
left(hour,10) || ' ' ||  right(hour, -11)                                  AS e
overlay(hour placing ' ' from 11)                                          AS f
to_timestamp(hour, 'YYYY-MM-DD-HH24:MI:SS')                                AS ts

SQL Fiddle.

按出现顺序从“限制性”到“廉价”。 ts 很特别。

一个

这就像currently accepted answer by @Zeki,在开头和结尾都加上了锚点^$,以使其更加不模糊并且可能更快。

您希望 \d 的特殊含义为 class shorthand 用于数字。 在 Postgres 中,不要使用 \\ 转义反斜杠 \。除非您使用早已过时的非默认设置 standard_conforming_strings = off 运行,否则这是不正确的。 Redshift 卡在了一个旧的开发阶段,就是这样做的。除非用另一个反斜杠转义,否则反斜杠会被解释。

b

\d\d\d2 更短更便宜。

c

使用字符类进行简化:数字 + 连字符:[\d-] 和数字 + 冒号:[\d:]

d

由于regexp_replace()没有第4个参数'g'只替换第一个匹配,你可以reverse()字符串,替换第一个连字符和reverse()后面。 在 Redshift 中不起作用,因为它使用 总是 替换所有出现的 simpler version of regexp_replace()

e

如果格式固定如图所示,只需取前 10 个字符、一个空格和字符串的其余部分。 Redshift 使用不接受负参数的simpler versions of left() and right(),所以我用substring() 代替。

f

或者,更简单一点,只是 overlay() 第 11 个字符加一个空格。Not implemented in Redshift.

ts

与其他类型不同,to_timestamp() 返回正确的 timestamp with time zone 类型,而不是 text。您也可以将结果分配给timestamp without time zone。 Details.。如果你想转换你的字符串,到目前为止最好的选择。 Not implemented in Redshift.

【讨论】:

不幸的是,没有一个问题给了我正确的答案。前 3 个(abc)根本没有改变结果。 4'th (d) - 删除了所有的-,所以时间戳看起来像这样2014 12 06 01:44:35。第 5 次 (e) 返回错误 context: Negative value given!。最后一个(f)返回,它不存在:function pg_catalog.overlay(character varying, "unknown", integer) does not exist @Vor:嗯,抱歉,Redshift 有更多限制。正如您在小提琴中看到的那样,这一切都适用于现代 Postgres。我为 Redshift 和解释添加了一些工作版本。 非常感谢您的详细解答【参考方案3】:
(\d4-\d2-\d2)-(\d2:\d2:\d2)

试试这个。替换为$1 $2。查看演示。

https://regex101.com/r/iY3eK8/13

【讨论】:

他们的输出正是我想要的。但是你能指导我在我的 sql 命令中改变什么(在正则表达式部分旁边) @Vor 在正则表达式旁边更改替换字符串。$1 $2\1 \2 我尝试过regexp_replace(hour, '(\d4-\d2-\d2)-(\d2:\d2:\d2)', '\1 \2')regexp_replace(hour, '(\d4-\d2-\d2)-(\d2:\d2:\d2)', '$1 $2'),但仍然没有给我正确的结果。 非常感谢您的帮助,您的回答是正确的,但就像@Zeki 建议的那样,我不得不转义它的反斜杠。

以上是关于正则表达式从 postgresql 中的时间戳字符串中间删除“-”的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL中的正则表达式无法按预期工作

PostgreSQL 正则表达式用条件替换函数

正则表达式从字符串中提取用户名/名称

正则表达式:从日志中选择 XML 消息和时间戳

正则表达式或 LIKE 模式的转义函数

如何使用正则表达式提取部分字符串