POSIX ERE正则表达式,用于查找重复的子串

时间:2017-10-02 18:11:12

标签: regex posix oracle-sqldeveloper regexp-substr posix-ere

我有一组包含最少1个和最多3个值的字符串,格式如下:

123;456;789
123;123;456
123;123;123
123;456;456
123;456;123

我正在尝试编写一个正则表达式,因此我可以在同一个字符串上找到重复的值,所以如果你有123;456;789,它会返回null,但如果你有123;456;456它将返回456并返回123;456;123返回123

我设法写了这个表达式:

(.*?);?([0-9]+);?(.*?)\2

它的工作原理是,当没有重复值但它没有返回我需要的值时返回null,例如:对于字符串123;456;456,它返回123;456;456 }对于字符串123;123;123,它返回123;123

我需要的是只返回表达式([0-9]+)部分的值,从我读过的内容通常是使用非捕获组完成的。但要么我做错了要么Oracle SQL不支持这个,好像我尝试使用?:语法,结果不是我所期望的。

关于如何在oracle sql上进行此操作的任何建议?此表达式的目的是在查询中使用它。

SELECT REGEXP_SUBSTR(column, "expression") FROM DUAL;

编辑:

实际上根据https://docs.oracle.com/cd/B12037_01/appdev.101/b10795/adfns_re.htm

  

Oracle数据库实现了符合POSIX扩展正则表达式(ERE)规范的正则表达式支持。

根据https://www.regular-expressions.info/refcapture.html

  

POSIX ERE不支持非捕获组

3 个答案:

答案 0 :(得分:1)

如果您只有三个子串,那么您可以使用强力方法。它不是特别漂亮,但它应该做的工作:

select (case when val1 in (val2, val3) then val1
             when val2 = val3 then val2
        end) as repeated
from (select t.*,
             regexp_substr(col, '[^;]+', 1, 1) as val1,
             regexp_substr(col, '[^;]+', 1, 2) as val2,
             regexp_substr(col, '[^;]+', 1, 3) as val3
      from t
     ) t
where val1 in (val2, val3) or val2 = val3;

答案 1 :(得分:1)

This answer介绍了如何从正则表达式中选择匹配的组。所以使用它,

SELECT regexp_substr(column, '(\d{3}).*\1', 1, 1, NULL, 1) from dual;
#                                                       ^ Select group 1

Working demo正则表达式(礼貌:OP)。

答案 2 :(得分:0)

请耐心等待,并考虑这种不同的方法。以稍微不同的方式查看问题并以一种方式对其进行细分,使您可以更灵活地查看数据。它可能适用于您的情况,也可能不适用于您的情况,但希望有趣的是要记住,总有不同的方法可以解决问题。

如果您将字符串转换为行,以便可以针对它们执行标准SQL,该怎么办?这样,您不仅可以计算重复的元素,还可以应用聚合函数来查找集合或其他内容的模式。

然后考虑一下。第一个公用表表达式(CTE)构建原始数据集。第二个,tbl_split,将该数据转换为列表中每个元素的行。取消注释紧随其后的选择以查看。最后一个查询从拆分数据中选择,显示元素在id数据中出现的频率计数。取消注释HAVING行,将输出限制为那些对您所追踪的数据出现多次的元素。

使用行中的数据,您可以看到如何将其他聚合函数应用于切片和切块以显示模式等。

SQL> with tbl_orig(id, str) as (
     select 1, '123;456;789' from dual union all
     select 2, '123;123;456' from dual union all
     select 3, '123;123;123' from dual union all
     select 4, '123;456;456' from dual union all
     select 5, '123;456;123' from dual
   ),
   tbl_split(id, element) as (
   select id,
          regexp_substr(str, '(.*?)(;|$)', 1, level, NULL, 1) element
   from tbl_orig
   connect by level <= regexp_count(str, ';')+1
   and prior id = id
   and prior sys_guid() is not null
   )
   --select * from tbl_split;
   select distinct id, element, count(element)
   from tbl_split
   group by id, element
   --having count(element) > 1
   order by id;

        ID ELEMENT     COUNT(ELEMENT)
---------- ----------- --------------
         1 123                      1
         1 456                      1
         1 789                      1
         2 123                      2
         2 456                      1
         3 123                      3
         4 123                      1
         4 456                      2
         5 123                      2
         5 456                      1

10 rows selected.

SQL>