【问题标题】: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-\\d{3}:\\w{2}',0);

但是得到了这个输出:

f-150:aa

Hive,我得到了NULL

【问题讨论】:

    标签: sql regex hive impala


    【解决方案1】:

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

    (?:(?:|(\\|))f-150|keep|those):|(?:^|\\|)\\w-\\d{3}:\\w{2}
    

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

    • 完全匹配应删除的元素,但仅匹配应保留的前缀。
    • 要保持分隔符不变,请将| 匹配到组 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|
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      • 2020-05-19
      • 2019-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多