plsql正则表达式删除带引号的引号之间的文本

时间:2013-04-15 10:30:04

标签: regex plsql

我正在努力使用正则表达式替换解决方案,该解决方案将删除VARCHAR2字段中引号之间的所有文本,即使这些引号之间的文本也引用了文本 例如文字:

'text start 'text inside' text end' leftover 'some other text'
正则表达式替换后的

应包含:leftover

我想出的是这段代码:

with tbl as (
  select
    '''text start ''text inside'' text end'' leftover ''some other text''' as str
    ,'\''(.*?)\''' as regex
  from dual
)
select
  tbl.str as strA
  ,regexp_replace(tbl.str,tbl.regex, '') as strB
from tbl; 

但子引号之间的文字仍然存在。

是否可以使用正则表达式实现此目的,还是应该在某个循环中拆分和分析内容? 一个理想的解决方案是它能否处理引用文本中引用文本的无限级别。

2 个答案:

答案 0 :(得分:1)

尝试

, '^[^'']*(''.*'')[^'']*$' as regex

警告:这将愚蠢地捕获捕获组1中测试文本中第一次和最后一次出现的单引号之间的所有内容,包括最外面的引号本身。特别是它没有检查正确的嵌套。

更重要的是,您的替换expr会更复杂:

, CASE WHEN REGEXP_INSTR(test, regex) > 0
     THEN REPLACE ( test, REGEXP_REPLACE(test, regex, '\1'), '' )
     ELSE test
  END

如果正则表达式匹配,则首先提取捕获组以在普通替换中使用(这是有效的,因为匹配的部分保证是最大的)。

重要提示:解决方案不会在您提供的特定上下文中产生所需的结果。但是,使用plsql regexp函数你无法做得更好,因为oracle正则表达式引擎不提供扩展来表达模式中的递归(例如.pcre do)。你需要这个工具来解决嵌套结构(即执行平衡计数)。

答案 1 :(得分:1)

  

理想的解决方案是,如果它可以处理引用文本中引用文本的无限级别出现。

用一个正则表达式是不可能的 Oracle中不提供递归正则表达式,也不提供递归捕获缓冲区。


UPD:
但它可以通过SQL完成:

with tbl as (
  select
    '''text start ''text inside'' text end'' leftover ''some other text''' 
    as str
  from dual
)
select
  listagg(text) within group (order by n) 
from 
  (
    select 
      n,
      sum(decode(regexp_replace(str, '^(.*?([<>])){'||n||'}.*$', '\2'),
        '<', 1, '>', -1, 0)) over (order by n) as nest,
      regexp_replace(str, '^(.*?[<>]){'||n||'}([^<>]*).*$', '\2') as text
    from 
      ( select regexp_replace(regexp_replace(str, '(\s|^)''', '\1<'), 
          '''(\s|$)', '>\1') as str from tbl ), 
      ( select level-1 as n from dual 
        connect by level-1 <= (select regexp_count(str, '''') from tbl) )
  )
where nest = 0

fiddle