【问题标题】:How is empty string and space treated in regular expression?正则表达式中如何处理空字符串和空格?
【发布时间】:2019-11-29 20:58:44
【问题描述】:

我试图使用 LISTAGG 和 REGEXP_REPLACE 函数连接不同的行值,如下面的链接所述: LISTAGG in Oracle to return distinct values。 试图了解发生了什么,我做了一些改变并开始使用它。然而,我没有得到我期待的答案。似乎我缺少一些关于正则表达式引擎如何处理“空字符串”和“空格”的关键概念。有人可以逐步介绍一下正则表达式引擎如何处理以下示例查询中的 why_space_affected_here、why_space_affected_here、why_space_not_affected_here、matching_empty_string 和 why_space_not_affected 列?

select group_key
     , listagg(id, ', ') within group (order by id) as listagg_output`
     , regexp_replace(listagg(id, ', ') within group (order by id), '([^,]*)(, \1)+', '\1') as why_space_affected_here
     , regexp_replace(listagg(id, ', ') within group (order by id), '([^,]*)(,\1)+', '\1') as why_space_not_affected_here
     , regexp_replace(listagg(id, ', ') within group (order by id), '([^,]*)(, \1)+', 'T') as matching_empty_string
     , regexp_replace(listagg(id, ', ') within group (order by id), '([^,]*)(, \1)+($|,)', '\1\3') as why_space_not_affected
from (
    select 22 group_key, 1 id from dual
    union all
    select 22 group_key, 2 id from dual
    union all
    select 22 group_key,  3 id from dual
    union all
    select 22 group_key, 3 id from dual
    )
group by group_key;

我希望为 why_space_affected_here 列保留空间(下面给出的查询): regexp_replace(listagg(id, ', ') 组内 (按 id 排序), '([^,]*)(, \1)+', '\1') as why_space_affected_here

【问题讨论】:

  • 添加示例数据。添加预期输出。尝试缩短您的查询。

标签: sql regex oracle


【解决方案1】:
SELECT REGEXP_REPLACE( '1, 2, 3, 3', '([^,]*)(, \1)+', '\1') as why_space_affected_here
FROM DUAL

输出 123,因为第一个和第二个替换 ([^,]*) 匹配零宽度字符串,只有逗号和空格被替换为零宽度字符串,然后在第三个替换 ([^,]*) 匹配 33, 33 替换。

SELECT REGEXP_REPLACE( '1, 2, 3, 3', '([^,]*)(,\1)+', '\1') as why_space_not_affected_here
FROM DUAL

输出 1 2 3 作为第一个和第二个替换 ([^,]*) 匹配零宽度字符串,仅替换逗号,第三个替换 ([^,]*) 匹配空格,然后 3 并删除 , 3

SELECT REGEXP_REPLACE( '1, 2, 3, 3', '([^,]*)(, \1)+', 'T') as matching_empty_string
FROM DUAL

输出1T2TT - 这与您的第一个示例完全相同,但不是保留第一个捕获组,而是将所有内容替换为T

SELECT REGEXP_REPLACE( '1, 2, 3, 3', '([^,]*)(, \1)+($|,)', '\1\3') as why_space_not_affected
FROM DUAL

([^,]*) 匹配3 并且($|,) 匹配字符串的结尾时,输出1, 2, 3,因为它的第一个匹配是3, 3


您能否描述或指导我了解第一个和第二个替换如何匹配零宽度字符串?

对于正则表达式([^,]*)(, \1)+ 然后[^,] 匹配非逗号字符。 [^,]* 匹配零个或多个非逗号字符。

  • 从字符串的开头:
    1, 2, 3, 3
    ^^^^
    
    ([^,]*) 可以匹配 1,但后面是 , 2 而不是 , 1,所以这将不匹配整个模式。
  • 仍然在字符串的开头:

    1, 2, 3, 3
    ^
    

    ([^,]*) 可以匹配零宽度(空)子字符串,但下一个字符是1 而不是,,因此这不会匹配整个模式并且尝试了所有可能的匹配模式匹配器将从下一个字符开始进行测试。

  • 从下一个字符开始移动:

    1, 2, 3, 3
     ^^
    

    ([^,]*) 无法匹配逗号,但它可以匹配零宽度(空)字符串,该字符串后面是逗号,然后是空格,然后是第一个匹配项的重复,即零宽度子字符串。所以该模式将成功匹配一个逗号和一个空格。

  • 2 开始,我们有效地重复前面的步骤,最终跳过2 字符并匹配零宽度子字符串,然后是逗号,然后是空格,然后是重复的零宽度子字符串。

【讨论】:

  • 感谢您的回答,@MT0!我知道第三个替换 ([^,]*) 如何匹配 3 和 3,3 仅替换为 3。我没有得到的是第一个和第二个替换 ([^,]*) 如何匹配零宽度字符串,只有逗号和空格是在以下查询中替换为零宽度字符串:SELECT REGEXP_REPLACE( '1, 2, 3, 3', '([^,]*)(, \1)+', 'T') as matching_empty_string FROM DUAL。您能否描述或引导我了解第一个和第二个替换如何匹配零宽度字符串?抱歉,这对我来说有点陌生。
猜你喜欢
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
  • 2019-09-04
  • 1970-01-01
  • 2021-12-22
  • 2021-07-04
相关资源
最近更新 更多