如何在 PL/sql 中实现 NegEx?

Posted

技术标签:

【中文标题】如何在 PL/sql 中实现 NegEx?【英文标题】:How to implement NegEx in PL/sql? 【发布时间】:2013-08-31 19:38:17 【问题描述】:

我在正则表达式方面的技能充其量是微不足道的。但是,我有一项任务需要阅读医学类型的文本,并标记不同类型的单词。此外,我需要确定该术语是否被否定。似乎有一组用 Python 编写并移植到 Java 的例程来执行我需要的类型的事情。它们被称为 Context/Negex,可以在这里找到; Google Code Negex Project

我可以阅读 Java,并且我了解他们正在尝试做的一些事情。我的理解是他们做一个术语扫描句子中的术语标记术语,然后遍历一组“否定短语”并标记否定术语,并将原始术语标记更改为否定。

我的第一个问题是,有人知道这种例程的 Oracle 端口吗? (一种选择是将 java 版本实现为 Oracle Java 存储过程,但我会发现很难修改和支持)。 如果没有,我有一个关于正则表达式的问题;

问题:在没有嵌套的情况下替换先前替换的子集。

假设我有一个包含的字符串;

狗象狗猫猫狗老鼠

然后我想标记两个短语

1) dog cat 
2) dog

编辑:需要将 dog 当作一个离散的词来处理,并且不会像下面这样匹配 dogfish 或 fishdog;

狗象狗猫猫狗狗鱼鱼狗老鼠

我会用“dog cat”替换所有“dog cat”;

dog elephant <term id=123 type=pos>dog cat</term> cat dog mouse

我现在需要替换所有术语“狗”,除了已经在任何以“”开头的标签中的“狗”产生:

<term id=456 type=pos>dog</term> elephant <term id=123 type=pos>dog cat</term> cat <term id=456 type=pos>dog</term> mouse

正则表达式可以做到这一点吗?如果是这样,会导致 regexp_replace 忽略 "" 标记中的任何内容的正则表达式是什么?

我将下面概述的方法实现为;

  FUNCTION ANNOTATE_ONE_TERM(IN_TEXT IN VARCHAR2, SEARCH_TERM IN VARCHAR2, TERM_TYPE IN VARCHAR2, RECORD_ID IN NUMBER) RETURN CLOB
  IS
    REGEX_SEARCH VARCHAR2(512);
    REGEX_REPLACE VARCHAR2(512);
  BEGIN
    REGEX_SEARCH := '((<TERM.*?</TERM>|[^<])*?)(^|\W)('|| SEARCH_TERM ||')($|\W)';
    REGEX_REPLACE := '\1 <TERM ID='|| TO_CHAR(RECORD_ID)||' TYPE=' || TERM_TYPE ||'>'|| SEARCH_TERM ||'</TERM> ';
    DBMS_OUTPUT.PUT_LINE('REGEX_SEARCH = ' || REGEX_SEARCH);
    DBMS_OUTPUT.PUT_LINE('REGEX_REPLACE = ' || REGEX_REPLACE);
    RETURN TRIM(REGEXP_REPLACE(IN_TEXT, REGEX_SEARCH, REGEX_REPLACE,1,0,'in'));
  END ANNOTATE_ONE_TERM;

它适用于示例文本,但是当我尝试使用更简单的字符串时,例如;

SELECT ANNOTATE_ONE_TERM(ANNOTATE_ONE_TERM(UPPER('elephant dog cat cat dogfish fishdog mouse'), 'DOG CAT', 'POS', 123),'DOG', 'POS',456) 
FROM DUAL;

我最终得到了;

ELEPHANT <TERM ID=123 TYPE=POS <TERM ID=456 TYPE=POS>DOG</TERM> CAT</TERM> CAT DOGFISH FISHDOG MOUSE

它似乎吃了一个尾随的“>”并嵌套了一个标签。

感谢所有额外的帮助。

【问题讨论】:

【参考方案1】:
regexp_replace(  
  'dog elephant <term id=123 type=pos>dog cat</term> cat dog mouse',
  '((<term.*?</term>|[^<])*?)dog', 
  '\1<term id=456 type=pos>dog</term>'
)

fiddle

【讨论】:

这很符合我的要求。不幸的是我不清楚。搜索字符串中的单词 dog 必须是离散单词,而不是另一个单词的一部分。所以它不应该匹配“dogfish”。我试过code'((|[^code 它有效,除了它吃了狗前后的空间。 我在上面的问题中添加了一些内容。如果您有时间,我将不胜感激。 \W 更改为空格字符。【参考方案2】:
REGEXP_REPLACE (
      REGEXP_REPLACE (source_string,
                      '(^| +)(dog cat)($| +)',
                      ' <term id=123 type=pos>\2</term> '),
      '(^| +)(dog)($| +)',
      ' <term id=456 type=pos>\2</term> ')

演示here.

【讨论】:

cat, dog, fish 呢? 这就是我使用 \W 而不是空格的原因。到目前为止,我最终做的是codetrim(regexp_replace('dog相dog cat cat dog dogfish mouse fishdog dog', '((|[^dog ' ))code

以上是关于如何在 PL/sql 中实现 NegEx?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式:如何在 PL/SQL 中实现负向后查找

PL/SQL-表和条件都不同时如何在单个查询中实现多条count语句

在 PL/SQL 中实现应用程序

在 pl/sql 过程中实现水平碎片表

有人可以帮我在 PL/SQL Oracle 中实现以下触发器吗?

PL/SQL 和 Oracle Forms Builder