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 变体?的主要内容,如果未能解决你的问题,请参考以下文章

SCSS 是不是支持内联注释?

[C/C++11]_[初级]_[使用正则表达式库regex]

MDK中嵌入汇编方法

gcc悄无声色将静态函数内联了

如何使用 __cpuid 检查 AES-NI 支持?

在 create table 语句中内联创建外键索引的语法