【问题标题】:remove specific word from string从字符串中删除特定单词
【发布时间】:2014-02-26 22:25:00
【问题描述】:

我正在使用oracle10g

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

例如,下面是我要删除的句子some

some text, 123 someone, another text some1

预期输出

 text, 123 someone, another text

请注意,如果some 单词包含some+ 除了A-Za-zsome 之前或之后的任何其他单词,我还想删除它。

这是我迄今为止尝试过的:

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 的答案。

【问题讨论】:

  • 您是否也必须处理“真实”序列?例如。序列,其中“some”是句子中的第一个词或最后一个词,因此可能前面没有任何内容/后面是句号“。”等等?
  • @FrankSchmitt 我想从句子中删除每个some,无需处理序列。每个some 不包含some +在A-Za-z 之间的开头和结尾的单词。

标签: sql regex oracle replace


【解决方案1】:

由于Oracle实现正则表达式时对lookbehind/lookaheadword boundary(\b)缺乏支持,单个REGEXP_REPLACE调用似乎无法满足所有要求。特别是 pointed out by 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

因为匹配模式中包含的用于匹配的分隔符(组 #1 和组 #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 example

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 感谢您的回答(和+1),在第一个和最后一个单词的句子前后添加空格可以部分解决问题,我已经尝试过了。但我也想删除像Some1Some,1some这样的单词,其中包含A-Za-z以外的单词。
    【解决方案3】:

    你可以使用REGEXP_REPLACE函数如下

    SELECT REGEXP_REPLACE('some text, 123 someone, another text some1', '(^|\s)some(^|\s)', '')
    FROM dual;
    

    SQL Fiddle Demo

    【讨论】:

    • 感谢您的回答(和 +1),这会从句子中删除 some,但我也想删除像 Some1 或 Some,或 1some 这样的单词,其中包含 AZ 或 az 以外的单词。
    • some some 字符串呢?
    • @EgorSkriptunoff 在这种情况下两者都应该被替换。
    【解决方案4】:

    使用REGEX_REPLACE()

    SELECT REGEXP_REPLACE('some other text someone other text, someB some1 some.', '(some\s|some\d|some[.])','')
    FROM dual;
    

    SQL Fiddle Demo

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

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

    【讨论】:

      【解决方案5】:

      类似的东西

      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

      【讨论】:

      • 单词的开头怎么样,例如'awesome' 并且单词末尾有多个数字? sqlfiddle illustration
      • @ThinkJet 感谢您的注意,是的,awesome 这个词不应该被替换,some123 应该被完全替换。如果您有任何解决方案或建议,请告诉我。
      • @ThinkJet 好吧,这只是一个关于如何实现 OP 想要的想法。像这样的场景可能还有 50 多个,OP 必须弄清楚这些场景并将其合并到代码中。
      猜你喜欢
      • 2014-07-03
      • 1970-01-01
      • 2021-12-13
      • 2018-12-22
      • 2021-05-22
      • 1970-01-01
      相关资源
      最近更新 更多