2013-04-15 101 views
0

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

'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; 

但子报价之间的文本仍然存在。

它甚至有可能用正则表达式来实现,还是应该在某个循环中分割和分析内容? 一个理想的解决方案是,如果它可以处理引用文本中的引用文本的无限级别事件。

回答

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

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),所以不能提供更好的功能。您需要使用此工具来解析嵌套构造(即执行平衡计数)。

相关问题