在 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 次出现的主要内容,如果未能解决你的问题,请参考以下文章