如何在 oracle 中转义特殊的正则表达式字符?
Posted
技术标签:
【中文标题】如何在 oracle 中转义特殊的正则表达式字符?【英文标题】:how to escape special regular expression characters in oracle? 【发布时间】:2013-09-20 11:56:14 【问题描述】:如何在Oracle中转义正则表达式模式的特殊字符?
例如,我需要一个翻译函数
some.string[with(special)reg-exp]characters
到
some\.string\[with\(special\)reg\-exp\]characters
。
在 php 中我会使用 preg_escape()。有 Oracle 对应的吗?
我为什么要这样做?
我正在尝试编写一个 pl/sql 函数来检查 string
是否在 list,of,string,elements
上。
这是我的代码:
CREATE OR REPLACE
FUNCTION list_contains(needle_ IN VARCHAR2,
haystack_ IN VARCHAR2,
separator_ IN VARCHAR2 DEFAULT ',')
RETURN INTEGER
IS
BEGIN
IF regexp_like(haystack_, '(^|' || separator_ || ')' || needle_ || '(' || separator_ || '|$)') THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END list_contains;
该功能基本有效:
list_conains('eve','john,eve,maria,steve') => 1
问题是当我尝试使用 needle_
或 separator_
的奇怪值来调用它时,例如 .
或其他在正则表达式中具有特殊含义的字符串。
list_conains('eve','john.maria.steve','.') => 1
如您所见,列表中没有 eve,但 .
与 steve 姓名的 t
字母匹配,因此该函数错误地返回 1
。
我知道我可以手动替换点,但是还有很多其他正则表达式特殊字符会干扰,我不想自己尝试列出所有字符。
如何摆脱needle_和separator_?
【问题讨论】:
【参考方案1】:如果我正确理解您的问题,您不需要正则表达式。您可以使用简单的 LIKE。
IF separator_ || haystack_ || separator_ LIKE '%'||separator_||needle_||separator_||'%' THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
编辑:如果%
或_
本身就是分隔符_,那么就需要对它们进行转义。
IF separator_ = '%' OR separator_ = '_'
THEN
separator_ := '\' || separator_;
END IF;
IF separator_ || haystack_ || separator_ LIKE
'%' || separator_ || needle_ || separator_ || '%' ESCAPE '\'
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
【讨论】:
谢谢。这是个好主意。我不知道我怎么看不到这个。似乎 11g 和它的新功能已经宠坏了我。我会用你的建议。但为了将来的使用,问题仍然有待解答。 您编辑后的解决方案并不完美,但我根据您的想法做了一些事情。IF separator_ || haystack_ || separator_ LIKE '%' || REPLACE(REPLACE(REPLACE(separator_ || needle_ || separator_, '\', '\\'), '%', '\%'), '_', '\_') || '%' ESCAPE '\' THEN
... 我这样做是为了确保 needle_ 和 separator_ 都安全逃脱。我还对转义字符进行了转义,以确保如果 needle_ 包含它,则不会对其进行特殊处理。【参考方案2】:
以下字符必须转义:\ ^ 。 $ | ( ) [ ] * + ? ,
http://psoug.org/snippet/Regular-Expressions--Regexp-Cheat-Sheet_856.htm
SELECT REGEXP_REPLACE('some.string[with(special)reg-exp]characters', '([][)(.$*+?,|^\])', '\\\1') "REGEXP_REPLACE" FROM dual;
【讨论】:
【参考方案3】:我认为在正则表达式语句中转义分隔符可能是最简单的。试试这个,它似乎对我有用:
IF regexp_like(haystack_, '(^|\' || separator_ || ')' || needle_ || '(\' || separator_ || '|$)') THEN
我改变的只是字符串构造中分隔符前面的斜线。
【讨论】:
虽然这适用于某些情况,但仍有可能 needle_ 包含特殊字符,因此您的答案不是一个完整的解决方案。不过还是谢谢你:)【参考方案4】:试试这个:
CREATE OR REPLACE
FUNCTION list_contains(needle_ IN VARCHAR2,
haystack_ IN VARCHAR2,
separator_ IN VARCHAR2 DEFAULT ',')
return number AS
l_return_count number := 0;
BEGIN
with haystack_ary as (
select extractvalue(x.column_value, 'e') as val
from xmltable ('e' passing xmlparse( content '<e>' || replace(haystack_, separator_, '</e><e>') || '</e>')) x
)
select
--count(1)
--return as a "bool"(1=true,0=false)
decode(count(1), 0, 0, 1)
into l_return_count
from haystack_ary
where lower(needle_) = lower(haystack_ary.val);
return l_return_count;
END;
我用较低的功能使它不区分大小写。如果你愿意,你也可以修剪空白:lower(trim(needle_)) = lower(trim(haystack_ary.val))
【讨论】:
【参考方案5】:这可以在没有任何正则表达式的情况下完成,并通过 instr 函数进行转义,如果不匹配将 返回 0,如果匹配则返回 > 0 .
为此,您应该在 needle_ 和 haystack_ 的开头和结尾添加 separator_,然后再检查 >haystack_ 包含 needle_。
概念证明
select haystack_, needle_, separator_, instr(separator_||haystack_||separator_, separator_||needle_||separator_) result_, expected_
from (
select 'john,eve,maria,steve' as haystack_ , 'eve' as needle_, ',' as separator_, '>0'as expected_ from dual union all
select 'john,eve,maria,steve' as haystack_ , 'john' as needle_, ',' as separator_, '>0'as expected_ from dual union all
select 'john,eve,maria,steve' as haystack_ , 'joh' as needle_, ',' as separator_, '=0'as expected_ from dual union all
select 'john,eve,maria,steve' as haystack_ , 'steve' as needle_, ',' as separator_, '>0'as expected_ from dual union all
select 'john,eve,maria,steve' as haystack_ , 'stev' as needle_, ',' as separator_, '=0'as expected_ from dual union all
select 'john,eve,maria,steve' as haystack_ , 'teve' as needle_, ',' as separator_, '=0'as expected_ from dual union all
select 'john.maria.steve' as haystack_ , 'eve' as needle_, '.' as separator_, '=0'as expected_ from dual union all
select 'john_maria_steve' as haystack_ , 'eve' as needle_, '_' as separator_, '=0'as expected_ from dual union all
select 'john%maria%steve' as haystack_ , 'eve' as needle_, '%' as separator_, '=0'as expected_ from dual
) t;
结果:
HAYSTACK_ NEEDLE_ SEPARATOR_ RESULT_ EXPECTED_
john,eve,maria,steve eve , 6 >0
john,eve,maria,steve john , 1 >0
john,eve,maria,steve joh , 0 =0
john,eve,maria,steve steve , 16 >0
john,eve,maria,steve stev , 0 =0
john,eve,maria,steve teve , 0 =0
john.maria.steve eve . 0 =0
john_maria_steve eve _ 0 =0
john%maria%steve eve % 0 =0
【讨论】:
以上是关于如何在 oracle 中转义特殊的正则表达式字符?的主要内容,如果未能解决你的问题,请参考以下文章