Oracle:是否有支持内联代码的REGEX_REPLACE变体?

时间:2015-04-01 17:21:18

标签: regex oracle plsql

注意:此问题最初是在c ++ regexp_replace的上下文中提出的(请参阅here)。然而,我想到它也可能对甲骨文宇宙感兴趣。该问题的措辞已获得原作者的许可。

Perl具有e正则表达式修饰符,它允许使用Perl代码而不仅仅是字符串来表示替换:http://perldoc.perl.org/perlretut.html#Search-and-replace尽管该示例并不是最好的,因为有切换来实现此目的。对于那些了解Perl的人来说,这是一个更有意义的例子:

$string = "StackOverflow user: Old Faithful";

$string =~ s/:\s*(.*)$/$1 == "Old Faithful" ? ": ".$1." is AWESOME!" : ": ".$1." is ???"/e;

print $string; #Will print "StackOverflow user: Old Faithful is AWESOME!"

(Pl)Sql中是否有regex_replace变体允许我做类似的事情?如代码内联替换。

1 个答案:

答案 0 :(得分:2)

不幸的是,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) := 'StackOverflow user: Old Faithful';
    text_orig_nay VARCHAR2(1000) := 'StackOverflow 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) := 'StackOverflow user: Old Faithful';
    text_orig_nay VARCHAR2(1000) := 'StackOverflow 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) := 'StackOverflow user: Old Faithful';
    text_orig_nay VARCHAR2(1000) := 'StackOverflow 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