我正在努力使用正则表达式替换解决方案,该解决方案将删除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;
但子引号之间的文字仍然存在。
是否可以使用正则表达式实现此目的,还是应该在某个循环中拆分和分析内容? 一个理想的解决方案是它能否处理引用文本中引用文本的无限级别。
答案 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