Oracle 正则表达式替换用逗号包围的字符串的多次出现
Posted
技术标签:
【中文标题】Oracle 正则表达式替换用逗号包围的字符串的多次出现【英文标题】:Oracle regex replace multiple occurrences of a string surrounded by commas 【发布时间】:2020-09-08 09:53:15 【问题描述】:我正在寻找一种方法来替换(删除/替换为'')Oracle SQL 数据库中的列中以逗号分隔的值列表中的字符串。例如,假设我有以下数据:
select ('SL,PK') as col1 from dual
union all
select ('PK,SL') as col1 from dual
union all
select ('SL,SL') as col1 from dual
union all
select ('SL') as col1 from dual
union all
select ('PK') as col1 from dual
union all
select ('PI,SL,PK') as col1 from dual
union all
select ('PI,SL,SL,PK') as col1 from dual
union all
select ('PI,SL,SL,SL,PK') as col1 from dual
union all
select ('PI,SL,SL,SL,SL,PK') as col1 from dual
union all
select ('PI,OSL,SL,PK') as col1 from dual
union all
select ('PI,SL,SLR,PK') as col1 from dual
COL1
-----
SL,PK
PK,SL
SL,SL
SL
PK
PI,SL,PK
PI,SL,SL,PK
PI,SL,SL,SL,PK
PI,SL,SL,SL,SL,PK
PI,OSL,SL,PK
PI,SL,SLR,PK
我希望将所有出现的子字符串“SL”严格(即不包括“OSL”)替换为空字符串''
。 理想的结果应该是这样的:
COL2
-----
,PK
PK,
,
(null)
PK
PI,,PK
PI,,,PK
PI,,,,PK
PI,,,,,PK
PI,OSL,,PK
PI,,SLR,PK
我曾尝试使用regexp_replace
函数,但它只会消除所有其他情况,即
SELECT
col1,
regexp_replace(col1,'(^|,)(SL)($|,)','\1' || '' || '\3',1,0,'imn') as col2
FROM (
SELECT ('SL,PK') as col1 FROM dual
UNION ALL
SELECT ('PK,SL') as col1 FROM dual
UNION ALL
SELECT ('SL,SL') as col1 FROM dual
UNION ALL
SELECT ('SL') as col1 FROM dual
UNION ALL
SELECT ('PK') as col1 FROM dual
UNION ALL
SELECT ('PI,SL,PK') as col1 FROM dual
UNION ALL
SELECT ('PI,SL,SL,PK') as col1 FROM dual
UNION ALL
SELECT ('PI,SL,SL,SL,PK') as col1 FROM dual
UNION ALL
SELECT ('PI,SL,SL,SL,SL,PK') as col1 FROM dual
UNION ALL
SELECT ('PI,OSL,SL,PK') as col1 FROM dual
UNION ALL
SELECT ('PI,SL,SLR,PK') as col1 FROM dual
)
COL1 COL2
----- -----
SL,PK ,PK
PK,SL PK,
SL,SL ,SL
SL (null)
PK PK
PI,SL,PK PI,,PK
PI,SL,SL,PK PI,,SL,PK
PI,SL,SL,SL,PK PI,,SL,,PK
PI,SL,SL,SL,SL,PK PI,,SL,,SL,PK
PI,OSL,SL,PK PI,OSL,,PK
PI,SL,SLR,PK PI,,SLR,PK
我已经在其他具有单词边界\b
构造的正则表达式实现中成功实现了我的目标,但还没有找到适用于 Oracle 正则表达式的解决方案。
更新
-
版本:我们使用的是 Oracle 版本 11g。
加法示例案例
PI,SL,SLR,PK
其他示例案例PK,SL
、SL,SL
、SL
、PK
【问题讨论】:
您使用什么版本的 Oracle? @wolφi 我很抱歉排除了该信息。我们在 11g 上。 【参考方案1】:因为 Oracle 的正则表达式在匹配后将匹配位置向前移动,不幸的是您需要执行两次正则表达式
regexp_replace(regexp_replace(col1,'(^|,)(SL)(\W|$)','\1\3',1,0,'imn') ,'(^|,)(SL)(\W|$)','\1\3',1,0,'imn')
【讨论】:
不幸的是,如果逗号之前的“SL”后面还有其他字母,这将不起作用。与前面可以有字母类似,如“OSL”示例中,后面可以有字母,即“SLR”。我也将此示例案例添加到问题中。 那么我认为没有比通过替换进行第二次传递更好的选择了。regexp_replace(regexp_replace(col1,'(^|,)(SL)(\W|$)','\1\3',1,0,'imn') ,'(^|,)(SL)(\W|$)','\1\3',1,0,'imn')
你提到这很有趣,这实际上是我在尝试不同场景时偶然发现的。如果您想将其添加为答案,我会接受。
单个 regexp_replace
是可能的(有一些 replace
pre 和后处理) - 请参阅替代答案。【参考方案2】:
如果您可以选择字符串中未出现的特殊字符 - 我使用的是分号 (;
),您可以按照以下步骤操作
1) 将每个逗号加倍为逗号 + 分号
2) 执行您的正则表达式,仅将分号作为可能的分隔符添加到模式中:
'(^|,|;)(SL)($|,|;)
3) 删除所有分号
完整的查询
SELECT
replace(regexp_replace(replace(col1,',',',;'),'(^|,|;)(SL)($|,|;)','\1\3',1,0,'imn'),';') as col2
FROM tab;
产生预期的结果
,PK
PK,
,
(null)
PK
PI,,PK
PI,,,PK
PI,,,,PK
PI,,,,,PK
PI,OSL,,PK
PI,,SLR,PK
【讨论】:
以上是关于Oracle 正则表达式替换用逗号包围的字符串的多次出现的主要内容,如果未能解决你的问题,请参考以下文章
利用notepad++正则表达式将 多个空格 替换为一个逗号