Regex:如何在PL/SQL中实现负查找

Regex:如何在PL/SQL中实现负查找,regex,plsql,negative-lookbehind,Regex,Plsql,Negative Lookbehind,如何匹配以loockup.开头、以\u 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;

如何匹配以
loockup.
开头、以
\u 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;
我需要确定是否至少有一个错误的
查找
,即除
查找之外的所有事件。msg_id
,还必须指定
键类型
参数。

使用
查找[^(]+([^m]]m[^s]]ms[^g])u id
,您基本上是要求检查字符串

  • 查找开始。
    查找\.
    表示
  • 后跟至少一个不同于
    的字符,由
    [^\(]+
    表示)
  • 后跟--
    (| |)
    • m
      不同的一个字符--
      [^m]
      ,或
    • 两个字符:
      m
      加上no
      s
      --
      m[^s]
      ,或
    • 三个字符:
      ms
      和no
      g
      --
      ms[^g]
      ,以及
  • \u id
    结尾,由
    \u id
    表示
  • 因此,对于
    lookup.msg_id
    ,第一部分显然匹配,第二部分消耗
    ms
    ,并将
    g
    留给第三部分的第一个备选方案

    这可以通过将第三部分修补为始终三个字符的长度来解决,如
    查找\.[^(]+([^m]..m[^s.]|ms[^g])\u id
    。但是,如果
    查找。
    \u 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)和REGEXP_计数(s'lookup\.[^\(]+_id')0

    为了代码清晰起见,
    REGEXP_INSTR(s,'lookup\.[^\(]+\u id')>0
    可能更可取


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

    要求仍然有点模糊

  • 在分号处拆分字符串
  • 检查每个子串
    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');|
    

  • 这将允许在右括号之前使用多余的逗号。但是如果输入语法正确,这样的逗号将不存在。

    是单个字符串还是多个字符串的串联?可以有很多级别,比如“lookup.tunnel.east.msg\u id”那么“lookup.tunnel.east.alternative\u msg\u id”呢需要nfo。不,只有一个级别。总是
    lookup.xyz_id(param1,param2,paramN)
    。感谢您的精彩回复。如果在同一字符串中出现更多的
    查找.xxx\u id
    ,该怎么办?在现实世界中,我需要检查可能包含任何数量的匹配或不匹配
    查找
    实例的源代码。@j3d您能提供更多详细信息吗?特别是:还有更多的“黑名单”吗不仅仅是
    lookup.msg_id
    ?如果字符串同时包含待匹配和不待匹配的令牌,那么预期的响应是什么?检查的更大目的是什么?@j3d我说得对吗:(I)最初,您想挑出
    msg
    令牌,以避免应用
    keytype
    检查?(ii)您需要检查语义,但不检查语法符合性-换句话说:例如,将不会缺少引号,但
    key\u type
    参数可能会丢失?(iii)对要遵守的值的任何其他限制(大小写、特殊字符(不允许)等)?只有在
    查找时,
    key\u type
    参数可能会丢失。
    后面跟着
    msg\u id
    。对于任何其他情况,必须指定
    key\u type
    参数(或者至少指定两个参数)。@j3d我想,更新中的
    资产:=
    中的第二个空格有错误?
    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');|