Oracle:是不是有支持内联代码的 REGEX_REPLACE 变体?
Posted
技术标签:
【中文标题】Oracle:是不是有支持内联代码的 REGEX_REPLACE 变体?【英文标题】:Oracle: Is There a Variant of REGEX_REPLACE that supports inline code?Oracle:是否有支持内联代码的 REGEX_REPLACE 变体? 【发布时间】:2015-04-01 17:21:17 【问题描述】:注意:这个问题最初是在 c++ regexp_replace
的上下文中提出的(参见 here)。但是,我突然想到,它可能对预言机世界也很感兴趣。问题的措辞已获得原作者的许可。
Perl 有 e
正则表达式修饰符,它允许 Perl 代码而不只是一个字符串来制定替换:http://perldoc.perl.org/perlretut.html#Search-and-replace 虽然这个例子不是最好的,因为有开关来完成这个。对于那些了解 Perl 的人来说,这里有一个更有意义的示例:
$string = "*** user: Old Faithful";
$string =~ s/:\s*(.*)$/$1 == "Old Faithful" ? ": ".$1." is AWESOME!" : ": ".$1." is ???"/e;
print $string; #Will print "*** user: Old Faithful is AWESOME!"
(Pl)Sql 中是否有一个regex_replace
变体可以让我做类似的事情?与替换的内联代码一样。
【问题讨论】:
【参考方案1】:很遗憾,REGEX_REPLACE
不支持动态生成的替换字符串。
但是,您可以靠近。这个答案包含相同想法的 3 个变体。简而言之:
变体 1:静态 最简单,仅用表达式语法计算,兼容 sql,性能噩梦
变体2:静态+函数调用
简单,复杂的计算,sql兼容,性能噩梦; 创建所需的功能/包的权限。
变体 3:动态 复杂,执行代码的最大灵活性,不兼容 sql,性能......你猜对了。
所有方法的基本思想是使用REGEXP_SUBSTR
来获取捕获组的内容,并将这些内容提供给计算实际用它替换的数据的代码。
在变体 1 中,此代码将是表达式本身,变体 2 将此代码隐藏在函数体中,而变体 3 将其实现为围绕它的动态 plsql 块。
变体 1(静态)
使用REGEXP_SUBSTR
获取捕获组内容并提供表达式以相应地处理此数据:
set serveroutput on
DECLARE
text_orig_yep VARCHAR2(1000) := '*** user: Old Faithful';
text_orig_nay VARCHAR2(1000) := '*** user: Some Nobody';
text_pattern VARCHAR2(1000) := ':\s*(.*)$';
text_repl VARCHAR2(1000);
BEGIN
text_repl :=
REGEXP_REPLACE (
text_orig_yep
, text_pattern
, CASE REGEXP_SUBSTR(text_orig_yep, text_pattern, 1, 1, '', 1)
WHEN 'Old Faithful' THEN REGEXP_SUBSTR(text_orig_yep, text_pattern, 1, 1, '', 1)||' is AWESOME!'
ELSE REGEXP_SUBSTR(text_orig_yep, text_pattern, 1, 1, '', 1)||' is ???'
END
);
dbms_output.put_line ( text_repl );
text_repl :=
REGEXP_REPLACE (
text_orig_nay
, text_pattern
, CASE REGEXP_SUBSTR(text_orig_nay, text_pattern, 1, 1, '', 1)
WHEN 'Old Faithful' THEN REGEXP_SUBSTR(text_orig_yep, text_pattern, 1, 1, '', 1)||' is AWESOME!'
ELSE REGEXP_SUBSTR(text_orig_yep, text_pattern, 1, 1, '', 1)||' is ???'
END
);
dbms_output.put_line ( text_repl );
END;
/
show error
变体 2(静态 + 函数调用)
使用REGEXP_SUBSTR
获取捕获组内容并提供一个函数来计算结果。通过这种方式,您可以执行复杂的计算,这些计算用 plsql 表达式表示是不可能或繁琐的。
set serveroutput on
CREATE OR REPLACE FUNCTION test_rreval ( match_1 IN VARCHAR2 ) RETURN VARCHAR2
IS
BEGIN
RETURN
CASE match_1
WHEN 'Old Faithful' THEN match_1||' is AWESOME!'
ELSE match_1||' is ???'
END
;
END test_rreval;
/
show error
DECLARE
text_orig_yep VARCHAR2(1000) := '*** user: Old Faithful';
text_orig_nay VARCHAR2(1000) := '*** user: Some Nobody';
text_pattern VARCHAR2(1000) := ':\s*(.*)$';
text_repl VARCHAR2(1000);
BEGIN
text_repl :=
REGEXP_REPLACE (
text_orig_yep
, text_pattern
, test_rreval ( REGEXP_SUBSTR(text_orig_yep, text_pattern, 1, 1, '', 1) )
);
dbms_output.put_line ( text_repl );
text_repl :=
REGEXP_REPLACE (
text_orig_nay
, text_pattern
, test_rreval ( REGEXP_SUBSTR(text_orig_nay, text_pattern, 1, 1, '', 1) )
);
dbms_output.put_line ( text_repl );
END;
/
show error
变体 3(动态)
您可以通过生成动态 plsql 块来生成结果,从而以性能和可维护性为代价获得最大的灵活性。作为一项额外福利,您可以更接近 perl 语法(但您可以相应地调整变体 2)。
set serveroutput on
DECLARE
text_orig_yep VARCHAR2(1000) := '*** user: Old Faithful';
text_orig_nay VARCHAR2(1000) := '*** user: Some Nobody';
text_pattern VARCHAR2(1000) := ':\s*(.*)$';
text_repl VARCHAR2(1000);
dyncode VARCHAR2(32000);
BEGIN
dyncode := 'DECLARE "$1" VARCHAR2(32000) := :1; BEGIN :outvar := REGEXP_REPLACE ( :text_orig, :text_pattern, CASE "$1" WHEN ''Old Faithful'' THEN "$1"||'' is AWESOME!'' ELSE "$1"||'' is ???'' END ); END;';
EXECUTE IMMEDIATE dyncode
USING IN REGEXP_SUBSTR(text_orig_yep, text_pattern, 1, 1, '', 1)
, OUT text_repl
, IN text_orig_yep
, IN text_pattern
;
dbms_output.put_line ( text_repl );
EXECUTE IMMEDIATE dyncode
USING IN REGEXP_SUBSTR(text_orig_nay, text_pattern, 1, 1, '', 1)
, OUT text_repl
, IN text_orig_nay
, IN text_pattern
;
dbms_output.put_line ( text_repl );
END;
/
show error
【讨论】:
以上是关于Oracle:是不是有支持内联代码的 REGEX_REPLACE 变体?的主要内容,如果未能解决你的问题,请参考以下文章