正则表达式:如何在PL / SQL中实现负面的Lookbehind

时间:2014-11-12 21:34:24

标签: regex plsql negative-lookbehind

如何匹配以loockup.开头并以_id结尾但不以msg为前缀的所有字符串?以下是一些例子:

lookup.asset_id -> should match
lookup.msg_id -> shouldn't match
lookup.whateverelse_id -> should match

我知道Oracle不支持负面的后观(即(?<!))...所以我试图使用交替显式枚举可能性:

regexp_count('i_asset := lookup.asset_id;', 'lookup\.[^\(]+([^m]|m[^s]|ms[^g])_id') <> 0 then
    dbms_output.put_line('match'); -- this matches as expected
end if;

regexp_count('i_msg := lookup.msg_id;', 'lookup\.[^\(]+([^m]|m[^s]|ms[^g])_id') <> 0 then
    dbms_output.put_line('match'); -- this shouldn’t match
                                   -- but it does like the previous example... why?
end if;

第二个regexp_count表达式不匹配......但它与第一​​个表达式相似。我错过了什么吗?

修改

在实际用例中,我有一个包含可能包含多个lookup.xxx_id实例的PL / SQL代码的字符串:

declare
    l_source_code varchar2(2048) := '
        ...
        curry := lookup.curry_id(key_val => ''CHF'', key_type => ''asset_iso'');
        asset : = lookup.asset_id(key_val => ''UBSN''); -- this is wrong since it does
                                                        -- not specify key_type
        ...
        msg := lookup.msg_id(key_val => ''hello''); -- this is fine since msg_id does
                                                    -- not require key_type
    ';
    ...
 end;

我需要确定是否至少有一个错误lookup,即除了lookup.msg_id之外的所有事件都必须指定key_type参数。

2 个答案:

答案 0 :(得分:1)

使用lookup\.[^\(]+([^m]|m[^s]|ms[^g])_id,您基本上要求检查字符串

  1. lookup.表示的lookup\.开头,
  2. 后跟至少一个与(表示的[^\(]+不同的字符,
  3. 后跟 - ( | | )
    • m - [^m]
    • 不同的一个字符
    • 两个字符:m加上没有s - m[^s]
    • 三个字符:ms而没有g - ms[^g]
  4. _id表示的_id结尾。
  5. 因此,对于lookup.msg_id,第一部分显然匹配,第二部分消耗ms,并留下g作为第三部分的第一部分。

    这可以通过修补第三部分来修复,总是像lookup\.[^\(]+([^m]..|m[^s.]|ms[^g])_id一样长三个字符。但是,如果lookup._id之间的部分长度不超过四个字符,那么这一切都会失败:

    WITH
    Input (s, r) AS (
      SELECT 'lookup.asset_id', 'should match' FROM DUAL UNION ALL
      SELECT 'lookup.msg_id', 'shouldn''t match' FROM DUAL UNION ALL
      SELECT 'lookup.whateverelse_id', 'should match' FROM DUAL UNION ALL
      SELECT 'lookup.a_id', 'should match' FROM DUAL UNION ALL
      SELECT 'lookup.ab_id', 'should match' FROM DUAL UNION ALL
      SELECT 'lookup.abc_id', 'should match' FROM DUAL
    )
    SELECT
      r, s, INSTR(s, 'lookup.msg_id') has_msg, REGEXP_COUNT(s , 'lookup\.[^\(]+([^m]..|m[^s]|ms[^g])_id') matched FROM Input
    ;
    
    |               R |                      S | HAS_MSG | MATCHED |
    |-----------------|------------------------|---------|---------|
    |    should match |        lookup.asset_id |       0 |       1 |
    | shouldn't match |          lookup.msg_id |       1 |       0 |
    |    should match | lookup.whateverelse_id |       0 |       1 |
    |    should match |            lookup.a_id |       0 |       0 |
    |    should match |           lookup.ab_id |       0 |       0 |
    |    should match |          lookup.abc_id |       0 |       0 |
    

    如果你只是要确定,相关位置没有msg,你可能想要去 (INSTR(s, 'lookup.msg_id') = 0) AND REGEXP_COUNT(s, 'lookup\.[^\(]+_id') <> 0

    代码清晰度REGEXP_INSTR(s, 'lookup\.[^\(]+_id') > 0可能更合适......

    @ j3d如果需要进一步的细节,请发表评论。

答案 1 :(得分:0)

由于要求仍然含糊不清......

  1. 以分号分隔字符串。
  2. 检查每个子字符串s是否符合:

    WITH Input (s) AS (
      SELECT '   curry := lookup.curry_id(key_val => ''CHF'', key_type => ''asset_iso'');' FROM DUAL UNION ALL
      SELECT 'curry := lookup.curry_id(key_val => ''CHF'', key_type => ''asset_iso'');' FROM DUAL UNION ALL
      SELECT 'asset := lookup.asset_id(key_val => ''UBSN'');' FROM DUAL UNION ALL
      SELECT 'msg := lookup.msg_id(key_val => ''hello'');' FROM DUAL
    )
    SELECT
      s
    FROM Input
    WHERE REGEXP_LIKE(s, '^\s*[a-z]+\s+:=\s+lookup\.msg_id\(key_val => ''[a-zA-Z0-9]+''\);$')
     OR
     ((REGEXP_INSTR(s, '^\s*[a-z]+\s+:=\s+lookup\.msg_id') = 0)
      AND (REGEXP_INSTR(s, '[(,]\s*key_type') > 0)
      AND (REGEXP_INSTR(s,
        '^\s*[a-z]+\s+:=\s+lookup\.[a-z]+_id\(( ?key_[a-z]+ => ''[a-zA-Z_]+?'',?)+\);$') > 0)) 
    ;
    
    
    |                                                                        S |
    |--------------------------------------------------------------------------|
    |[tab] curry := lookup.curry_id(key_val => 'CHF', key_type => 'asset_iso');|
    |      curry := lookup.curry_id(key_val => 'CHF', key_type => 'asset_iso');|
    |                                 msg := lookup.msg_id(key_val => 'hello');|
    
  3. 这将容忍在右括号之前的多余逗号。但是如果输入在语法上是正确的,那么这样的逗号将不存在。