从 PL/SQL 中的字符串中删除 LEADING 和 TRAILING 关键字

Posted

技术标签:

【中文标题】从 PL/SQL 中的字符串中删除 LEADING 和 TRAILING 关键字【英文标题】:Removing LEADING and TRAILING keywords from a String in PL/SQL 【发布时间】:2014-09-07 12:57:08 【问题描述】:

我需要从输入字符串中删除某些关键字并返回新字符串。关键字存储在另一个表中,例如 MR, MRS, DR, PVT, PRIVATE, CO, COMPANY, LTD, LIMITED 等。它们是两种关键字 LEADING - MR, MRS, DR 和 TRAILING - PVT, PRIVATE, CO, COMPANY, LTD, LIMITED 等。

因此,如果关键字是 LEADING,那么我们必须从开头删除它,如果它是 TRAILING,那么我们必须从末尾删除它。例如-MR Jones MRS COMPANY 应该返回 JONES MRSMR MRS Jones PVT COMPANY 应该返回 MRS JONES PVT (在第一次迭代中,MR 和 PVT 将被修剪,然后单词将变为 MRS JONES PVT)它应该只删除第一次出现的保留关键字无论是在输入字符串的开头还是结尾,因此在开头多次出现 LEADING 关键字时,它应该只删除第一个而不是像我上面给出的示例那样的其他关键字,对于 TRAILING 关键字也是如此。

我已经编写了下面的函数,它工作正常,但效率不高,我相信它的性能可以提高很多(可能使用正则表达式)。下面是函数:

CREATE OR REPLACE FUNCTION replace_keyword (p_in_name IN VARCHAR2)
RETURN VARCHAR2
 IS
 l_name   VARCHAR2 (4000);
 l_keyword_found BOOLEAN;

  CURSOR c IS
  SELECT *
    FROM RSRV_KEY_WORDS
   WHERE ACTIVE = 'Y'
   AND upper(POSITION)  in ('LEADING', 'TRAILING'); 

 BEGIN
 --Remove the leading and trailing blank spaces
 l_name := TRIM (UPPER (p_in_name)); 


 --remove LEADING keywords
   l_keyword_found := false;
   for rec in c LOOP
        IF     UPPER (rec.POSITION) = 'LEADING'
         AND SUBSTR(l_name, 1,INSTR(l_name,' ',1) - 1) = rec.key_word 
         AND l_keyword_found = false
        THEN 
            l_name := SUBSTR(l_name,INSTR(l_name,' ',1)+1);
            l_keyword_found := true;
        END IF;
        EXIT  WHEN (l_keyword_found);
   END LOOP;

 --Remove multiple spaces in a word and replace with single blank space
   l_name := REGEXP_REPLACE (l_name, '[[:space:]]2,', ' '); 
 --Remove the leading and trailing blank spaces
   l_name := TRIM (l_name);  

 --remove TRAILING keywords
   l_keyword_found := false;
   for rec in c LOOP
        IF     UPPER (rec.POSITION) = 'TRAILING'
         AND SUBSTR(l_name, INSTR(l_name,' ',-1) + 1) = rec.key_word
         AND l_keyword_found = false
        THEN 
            l_name := SUBSTR(l_name,1,INSTR(l_name,' ',-1)-1);  
            l_keyword_found := true;
        END IF;
        EXIT  WHEN (l_keyword_found);
   END LOOP;
 --Remove multiple spaces in a word and replace with single blank space
   l_name := REGEXP_REPLACE (l_name, '[[:space:]]2,', ' '); 
 --Remove the leading and trailing blank spaces
   l_name := TRIM (l_name); 
   return l_name;
 EXCEPTION
   WHEN OTHERS
   THEN
      raise_application_error (
         -20001,
         'An error was encountered - ' || SQLCODE || ' -ERROR- ' || SQLERRM);
 END;
/

【问题讨论】:

RSRV_KEY_WORDS 中前导和尾随关键字的潜在数量分别是多少? @JensKrogsboell:表中总共有大约 40 条记录。 【参考方案1】:

我真的不能说这是否会更快,但我会试一试:

假设 RSRV_KEY_WORDS 中的关键字不经常更改,我将创建一个函数来从表中生成正则表达式并让 Oracle 缓存结果:

create or replace function get_lead_and_trail_regexp return varchar2 
  result_cache relies_on (RSRV_KEY_WORDS) is
declare
   CURSOR c IS
     SELECT ( SELECT listagg(key_word,'|') within group (order by 1)
              FROM   RSRV_KEY_WORDS
              WHERE  ACTIVE = 'Y'
              AND    upper(POSITION) = 'LEADING' ) as leading,
            ( SELECT listagg(key_word,'|') within group (order by 1)
              FROM   RSRV_KEY_WORDS
              WHERE  ACTIVE = 'Y'
              AND    upper(POSITION) = 'TRAILING' ) as trailing
     FROM dual;
begin
  for rec in c loop
    return '(^[ ]+(('||rec.leading||')[ ]+))|([ ]+(('||rec.trailing||'||)[ ]+)$)';
  end loop;
  return null; -- Not very likely
end get_lead_and_trail_regexp;

然后您可以使用正则表达式一次性删除第一个前导和第一个尾随关键字:

l_name := REGEXP_REPLACE (l_name, get_lead_and_trail_regexp , ' ');

然后携带一个删除所有重复的空格。

我已经使用 java.lang.String.replaceAll 测试了正则表达式,因为我目前没有可用的 Oracle 数据库,但我相信它也可以使用 REGEXP_REPLACE。

【讨论】:

请注意,listagg 函数不能产生超过 4000 个字符的结果 - 因此限制了表中的关键字数量。

以上是关于从 PL/SQL 中的字符串中删除 LEADING 和 TRAILING 关键字的主要内容,如果未能解决你的问题,请参考以下文章

替换 PL/SQL 中的几行正则表达式函数

如何从 PL\SQL 中的字符串中选择最后 3 个单词?

pl/sql 从数字到字符串的转换

Oracle pl/sql:在事务中执行动态删除

使用 PL SQL 删除

PL/SQL 逗号分隔列表;删除重复并放入数组