从字符串中删除特定单词

4

我正在使用 oracle10g

我想从句子中删除特定单词的所有出现,但我不想删除包含其他字符(a-z或A-Z)之间的任何其他单词。

例如,以下是一句话,我想要删除其中的some

some text, 123 someone, another text some1

期望输出:

 text, 123 someone, another text

请注意,如果“some”单词包含除“A-Z”和“a-z”之外的任何其他字符,则我还想将其删除,并且这些字符在“some”之前或之后存在。下面是我迄今为止尝试过的方法:
select replace('some text, 123 someone, another text some1','some','') 
from dual;

我得到的输出是:
 text, 123 one, another text 1

在上面的输出中,我希望someone不被替换,而some1应该完全被替换。
我应该如何实现这一点?任何建议都将不胜感激。 编辑:为了清晰起见,这是我要寻找的另一个示例:
some other text someone other text, someB some1 some.

输出应该是:
 other text someone other text, someB 

从上面的句子中我们可以看到,someB没有被删除是因为它之间有字符a-z
some1some.则被删除了,因为它们之间没有a-z

编辑2

如果我使用正则表达式:

select REGEXP_REPLACE('some text, 123 someone, another text some1','[^a-zA-Z]','')
from dual

我得到的输出是:
sometextsomeoneanothertextsome

期望输出:

sometextsomeoneanothertext

请注意,我希望字符串中的some1也被移除,因为它包含除A-Z之外的其他字符。欢迎使用regex进行回答。

你是否需要处理“真实”的序列?例如,一些单词可能是句子的第一个或最后一个单词,因此可能在前面没有任何内容或在后面跟着一个句号“。”等等。 - Frank Schmitt
@FrankSchmitt 我想从句子中删除每个 some,不需要处理顺序。每个 some 都不包含在开头和结尾处没有 A-Za-z 之间的单词。 - Bhushan
5个回答

4
由于 Oracle 实现的正则表达式不支持 回顾/前瞻单词边界(\b),似乎不可能在单个 REGEXP_REPLACE 调用中满足所有要求。特别是对于 Egor Skriptunoff 指出的情况:模式匹配,后面跟着一个分隔符,像 some some some some ...
没有这种情况,可以使用此调用匹配所有这样的字符串:
regexp_replace(
  source_string,                                       -- source string
  '([^[:alnum:]]|^)((\d)*some(\d)*)([^[:alnum:]]|$)',  -- pattern
  '\1\5',                                              -- leave separators in place
  1,                                                   -- start from beginning
  0,                                                   -- replace all occurences
  'im'                                                 -- case-insensitive and multiline 
);

模式部件:

(                -- start of Group #1
  [^[:alnum:]]   -- any non-alphanumeric character 
  |              -- or 
  ^              -- start of string or start of line 
)                -- end of Group #1
(                -- start of Group #2
  (              -- start of Group #3 
    \d           -- any digit
  )              -- end of Group #3
  *              -- include in previous group zero or more consecutive digits
  some           -- core string to match
  (              -- start of group #4
    \d           -- any digit
  )              -- end of group #4  
  *              -- include in previous group zero or more consecutive digits
)                -- end of Group #2
(                -- start of Group #5
  [^[:alnum:]]   -- any non-alphanumeric character 
  |              -- or
  $              -- end of string or end of line
)                -- end of Group #5

因为用于匹配的分隔符(第一组和第五组)包含在匹配模式中,所以在成功匹配后,它们将从源字符串中删除,因此我们需要通过在第三个regexp_replace参数中指定来恢复这些部分。

基于这个解决方案,甚至可以在循环内替换所有的、重复出现的情况。

例如,您可以定义一个如下的函数:

create or replace function delete_str_with_digits(
  pSourceString in varchar2, 
  pReplacePart  in varchar2  -- base string (like 'some' in question)
)
  return varchar2
is
  C_PATTERN_START constant varchar2(100) := '([^[:alnum:]]|^)((\d)*';
  C_PATTERN_END   constant varchar2(100) := '(\d)*)([^[:alnum:]]|$)';

  vPattern         varchar2(4000);
  vCurValue        varchar2(4000);
  vPatternPosition binary_integer;
begin

  vPattern := C_PATTERN_START || pReplacePart || C_PATTERN_END;
  vCurValue := pSourceString;

  vPatternPosition := regexp_instr(vCurValue, vPattern);

  while(vPatternPosition > 0) loop
    vCurValue := regexp_replace(vCurValue, vPattern,'\1\5',1,0,'im');
    vPatternPosition := regexp_instr(vCurValue, vPattern);
  end loop;

  return vCurValue;  

end;

并将其与 SQL 或其他 PL/SQL 代码一起使用:

SELECT 
  delete_str_with_digits(
    'some text, -> awesome <- 123 someone, 3some3
     line of 7 :> some some some some some some some <
222some  another some1? some22 text 0some000', 
    'some'
  )  as result_string
FROM 
  dual

SQLFiddle示例


3

以下是一种不使用正则表达式的方法:

select trim(replace(' '||'some text, 123 someone, another text some1'||' ',
                    ' some ',' '
                   ) 
           )
from dual;

1
感谢您的回答(加上+1),在第一个和最后一个单词之前添加空格部分地解决了问题,我已经尝试过了。但我还想删除像“Some1”或“Some,”或“1some”这样包含除“A-Z”或“a-z”以外的单词的单词。 - Bhushan

1
您可以按以下方式使用REGEXP_REPLACE函数。
SELECT REGEXP_REPLACE('some text, 123 someone, another text some1', '(^|\s)some(^|\s)', '')
FROM dual;

SQL Fiddle演示


感谢您的回答(加上+1),这将从句子中删除“some”。但我还想删除像Some1或Some或1some这样包含除A-Z或a-z以外的单词的单词。 - Bhushan
some some 字符串怎么样? - Egor Skriptunoff
在这种情况下,两者都应该被替换。 - Bhushan

1
使用REGEX_REPLACE()如下:
SELECT REGEXP_REPLACE('some other text someone other text, someB some1 some.', '(some\s|some\d|some[.])','')
FROM dual;

SQL Fiddle演示

希望这有所帮助。如果有帮助,请将其标记为答案 :)

如果您想要匹配除.以外的任何其他字符,则只需将其添加到最后一个[]中,例如,如果您还想匹配一些#,则可以像这样将其添加到.中:[.#]


1
像这样的东西
SELECT REGEXP_REPLACE('some text, 123 someone, another text some1 some@, SOMEone SoME1', 
                      '(some\d|some[^[:alnum:]]|some$)','',1,0,'i')
FROM dual;

输出:

text, 123 someone, another text , SOMEone

以下是模式和选项的解释:

  1. some\d - 单词 "some" 后跟任何数字。
  2. some[^[:alnum:]] - 单词 "some" 后跟任何非字母数字字符。 ^ 代表否定,[:alnum:] 代表字母数字。所以基本上,[^[:alnum:]][[:alnum:]] 的相反。
  3. some$ 如果字符串以单词 "some" 结尾。
  4. 1,0,'i' - 从第一个出现的 1 开始,后面跟随所有出现的 0 ,并且不区分大小写 i

2
单词的开头怎么办,例如 'awesome',以及单词末尾超过一个数字怎么处理?sqlfiddle演示 - ThinkJet
@ThinkJet感谢您的留言,是的,“awesome”一词不应替换,而“some123”应完全替换。如果您有任何解决方案或建议,请告诉我。 - Bhushan
@ThinkJet 嗯,这只是实现 OP 想要的东西的一种思路。可能还有50多种类似的情况,OP必须在代码中加以考虑和整合。 - Anjan Biswas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接