从 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 MRS
和 MR 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 关键字的主要内容,如果未能解决你的问题,请参考以下文章