在 SQL (Presto) 中的字符串中查找模式的第 n 次出现

Posted

技术标签:

【中文标题】在 SQL (Presto) 中的字符串中查找模式的第 n 次出现【英文标题】:Finding nth occurrence of a pattern within a string in SQL (Presto) 【发布时间】:2021-05-19 20:36:29 【问题描述】:

我正在使用函数 regexp_extract 在 Presto SQL 中编写查询

我有一个可能类似于以下示例的字符串:

'1A2B2C3D3E'
'1A1B2C2D3E'
'1A2B1C2D2E'

我要做的是找到例如 second 出现的 1[A-E]。

如果我尝试

regexp_extract(col, '(1[A-E])(1[A-E])', 2)

这将适用于第二个示例(第一个示例,因为它没有返回任何内容,因为没有第二次出现)。但是,这对于第三个示例将失败。它什么也不返回。我知道这是因为我的正则表达式正在搜索一个 1[A-E],直接 后面跟着另一个 1[A-E]。

然后我尝试了

regexp_extract(col, '(1[A-E])(.*)(1[A-E])', 3)

但这也不起作用。我不确定如何解释我可能有 1A1B2C 或 1A2B1C 来找到第二个 1。有什么帮助吗?

【问题讨论】:

我不了解 Presto,但您的第二种模式看起来应该可以工作。唯一的问题是您应该使用惰性量词(即.*? 而不是.*)否则第 3 组将包含 last 出现,不一定是 second一。 “不起作用”到底是什么意思?你有任何结果吗? 【参考方案1】:

您的第二个模式在最新版本的 Trino (formerly known as Presto SQL) 中确实有效:

WITH t(col) AS (
  VALUES 
    '1A2B2C3D3E', 
    '1A1B2C2D3E',
    '1A2B1C2D2E')
SELECT regexp_extract(col, '(1[A-E])(.*)(1[A-E])', 3)
FROM t
 _col0
-------
 NULL
 1B
 1C
(3 rows)

正如其他人评论的那样,对于第一次匹配或 .*,您不需要捕获组,并且您应该使用惰性量词来避免 .* 急切匹配第一次和最后一次出现之间的所有字符:

WITH t(col) AS (
    VALUES 
        '1A2B2C3D3E', 
        '1A1B2C2D3E',
        '1A2B1C2D2E', 
        '1A2B1C2D1E') 
SELECT regexp_extract(col, '1[A-E].*?(1[A-E])', 1)
FROM t
 _col0
-------
 NULL
 1B
 1C
 1C
(4 rows)

【讨论】:

【参考方案2】:

您不需要第二个捕获组 (.*) 将 2 个捕获组保留在结果中,您可以选择匹配其间允许的字符。

根据我在this page 上阅读的内容,您还可以考虑使用regexp_extract_all 来获取所有匹配项,因为regexp_extract 返回第一个匹配项。

由于示例数据由一个数字后跟一个字符 A-E 组成,因此您可以从字符类中排除匹配 1 以防止过度匹配和回溯。

(1[A-E])[02-9A-E]*(1[A-E])

Regex demo

如果使用单个捕获组获取第二个值也可以,可以使用

1[A-E][02-9A-E]*(1[A-E])

Regex demo

【讨论】:

是什么让 OP 的原始模式“不起作用”? @41686d6564 我认为使用regexp_extract 而不是regexp_extract_all,但我没有使用presto 的经验。 感谢您的帮助。不幸的是,我正在编写此查询的程序不允许我使用 regex_extract_all。更糟糕的是,由于某种原因,您的解决方案在该程序中不起作用(即使我认为它是正确的)。在带有 [0-9A-E]* 的部分,有没有办法排除 1?所以它只搜索0、2-9?抱歉,正则表达式不太好 @user9592573 “有办法排除 1 吗?” 这不正是这个答案中的第二个模式吗? @user9592573 如果获取第二个值的单个组也可以,可以使用1[A-E][02-9A-E]*(1[A-E])regex101.com/r/F4T6Bk/1

以上是关于在 SQL (Presto) 中的字符串中查找模式的第 n 次出现的主要内容,如果未能解决你的问题,请参考以下文章

从 Presto SQL 中的字符串获取日期

SQL 注释中的 Java 正则表达式查找/替换模式

如何运行 Presto 查询查找行数组中元素的索引

从字段 sql/presto 中提取子字符串

在某个单词 Presto SQL 之后提取一个字符串

使用 MySQL/Presto 提取给定开始和结束模式的字符串