删除元素的正则表达式与特定前缀不匹配

Posted

技术标签:

【中文标题】删除元素的正则表达式与特定前缀不匹配【英文标题】:Regular expression to remove element not match specific prefix 【发布时间】:2018-06-27 22:59:29 【问题描述】:

我在 Impala 或 Hive 中执行此操作。基本上假设我有一个这样的字符串

f-150:aa|f-150:cc|g-210:dd

每个元素由管道| 分隔。每个都有前缀f-150 或其他。我希望能够删除前缀并仅保留与特定前缀匹配的元素。比如前缀是f-150,我希望regex_replace后面的最后一个字符串是

aa|cc

dd 被移除,因为g-210 是不同的前缀并且不匹配,因此整个元素被移除。

知道如何在一个 SQL 中使用字符串表达式来做到这一点吗?

谢谢

更新 1

我在Impala中试过这个:

select regexp_extract('f-150:aa|f-150:cc|g-210:dd','(?:(?:|(\\|))f-150|keep|those):|(?:^|\\|)\\w-\\d3:\\w2',0);

但是得到了这个输出:

f-150:aa

Hive,我得到了NULL

【问题讨论】:

【参考方案1】:

有问题的正则表达式可能如下所示:

(?:(?:|(\\|))f-150|keep|those):|(?:^|\\|)\\w-\\d3:\\w2

我添加了一些伪关键字来保留,但我相信你明白了:

完全匹配应删除的元素,但仅匹配应保留的前缀。 要保持分隔符不变,请将| 匹配到组 1 中元素的开头,然后用$1 将其放回替换位置。

Demo

根据documentation,您的查询应该写成Java regex;同样,这应该像这样code sample in Java。

【讨论】:

感谢您的帮助。我在网上其他地方尝试了正则表达式,它可以工作,但由于某种原因在 Impala 和 Hive 中,它没有。请看我上面的更新。【参考方案2】:

您可以匹配要删除的值,然后用空字符串替换:

f-150:|\|[^:]+:[^|]+$|[^|]+:[^|]+\|

f-150:|\\|[^:]+:[^|]+$|[^|]+:[^|]+\\|

解释

f-150: 字面匹配 |或者 \|[^:]+:[^|]+$ 匹配一个管道,而不是冒号一次或多次,后跟非管道一次或多次并断言行尾 |或者 [^|]+:[^|]+\| 不匹配管道一次或多次,冒号后跟非管道匹配一次或多次,然后匹配管道

Test with multiple lines and combinations

【讨论】:

由于某种原因,Impala 在执行select regexp_extract('f-150:aa|f-150:cc|g-210:dd','f-150:|\\|[^:]+:[^|]+$|[^|]+:[^|]+\\|',0); 时一直只提供f-150:aa| 如果你使用 regexp_replace,也许像regexp_replace("f-150:aa|f-150:cc|g-210:dd", "f-150:|\\|[^:]+:[^|]+$|[^|]+:[^|]+\\|", "") 我跑了select regexp_replace('f-150:aa|f-150:cc|g-210:dd','f-150:|\\|[^:]+:[^|]+$|[^|]+:[^|]+\\|','NA');,得到了NANAg-210:dd,所以看起来它做对了。 我想如果有可能作为解决方法,我可以用空字符替换“none f-150”。基本上g-210:dd 会被清空。【参考方案3】:

您可能必须遍历字符串直到结束才能获得所有匹配的子字符串。大多数 sql 不支持前瞻语法,因此上述正则表达式可能不适合 SQL 语法。出于您的目的,您可以执行一些操作,例如创建一个循环遍历的表,以模仿 Oracle 的级别语法并与包含字符串的表连接。

With loop_tab as (
Select 1 loop union all
Select 2 union all
select 3 union all
select 4 union all
select 5),
string_tab as(Select 'f-150:aa|ade|f-150:ce|akg|f-150:bb|'::varchar(40) as str)
Select regexp_substr(str,'(f\\-150\\:\\w+\\|)',1,loop)
from string_tab
join loop_tab on 1=1

输出:

regexp_substr
f-150:aa|
f-150:ce|
f-150:bb|

【讨论】:

以上是关于删除元素的正则表达式与特定前缀不匹配的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式前瞻(?=)后顾(?<)负前缀(?!)负后顾(?<!)

正则表达式与特定模式完全匹配 10 位数字

正则表达式 - 如何匹配除特定模式之外的所有内容

正则表达式:如何匹配不以前缀列表开头的子字符串

正则表达式匹配非零前缀数字 *OR* 字母数字

30分钟带你掌握正则表达式