REGEXP_REPLACE不会发生连续模式替换

时间:2018-06-05 13:14:28

标签: sql oracle regexp-replace

我有一个字符串,如下所示

Welcome to the world of the Hackers

我正在尝试使用以下查询替换整个字符串之间列出的字符串的出现,即of,to,the,但如果模式是连续的,则它无法正常工作,它会失败。

SELECT regexp_replace( 'Welcome to the world of the Hackers', '( to )|( the )|( of )', ' ' ) 
FROM dual;

输出:Welcome the world the Hackers

即使模式连续重复,也无法正常工作,即

SELECT regexp_replace( 'Welcome to to the world of the Hackers', '( to )|( the )|( of )', ' ' ) 
FROM dual;

输出:Welcome to world the Hackers

而我的预期输出是:Welcome world Hackers

使用REGEXP_REPLACE是否有替代方案/解决方案?

2 个答案:

答案 0 :(得分:3)

您可以使用正则表达式(^|\s+)((to|the|of)(\s+|$))+

SQL Fiddle

查询1

WITH test_data ( sentence ) AS (
  SELECT 'to the of' FROM DUAL UNION ALL
  SELECT 'woof breathe toto' FROM DUAL UNION ALL -- has all the words as sub-strings of words
  SELECT 'theory of the offer to total' FROM DUAL -- mix of words to replace and words starting with those words
)
SELECT sentence,
       regexp_replace(
         sentence,
         '(^|\s+)((to|the|of)(\s+|$))+',
         '\1'
       ) AS replaced
FROM   test_data

<强> Results

|                     SENTENCE |           REPLACED |
|------------------------------|--------------------|
|                    to the of |             (null) | -- All words replaced
|            woof breathe toto |  woof breathe toto |
| theory of the offer to total | theory offer total |
  

为什么regexp_replace( 'Welcome to the world of the Hackers', '( to )|( the )|( of )', ' ' )不能用于连续匹配?

因为正则表达式解析器将在第一次匹配结束后之后查找第二个匹配,并且在查找后续匹配时不会包含已解析的字符串部分或替换文本。< / p>

所以第一场比赛将是:

 'Welcome to the world of the Hackers'
         ^^^^

第二场比赛将在该比赛后的子字符串中查看

 'the world of the Hackers'
           ^^^^

子字符串开头的'the '将不会匹配,因为它没有前导空格字符(是的,之前有一个空格但是在上一个匹配中匹配了,是的,那个匹配被替换为空格但重叠的匹配和先前替换的匹配不是正则表达式的工作方式。)

所以第二个匹配是剩余子字符串中间的' of '

没有第三个匹配,因为剩余的未解析的子字符串是:

'the Hackers'

并且,'the '不匹配,因为没有要匹配的前导空格字符。

答案 1 :(得分:2)

REGEXP_REPLACE与第二个模式不匹配,后者是已匹配模式的一部分。当您使用像|这样的多模式匹配时,这一点更加明显。因此,您不能依赖空格来使用单词边界来匹配多个模式。一种解决方案可以是分割和组合字符。这可能不是最好的方式,但仍然有效。我很高兴知道一个更好的解决方案。

这也假设当组合字符串中的单个空格在原始字符串中有多个空格时,您可以正常使用。此外,不考虑以逗号或分号结尾的单词。对于此类情况,您可以使用NOT REGEXP_LIKE代替NOT IN进行增强。

WITH t (id,s)
AS (
    SELECT 1 , 'Welcome to the world of the Hackers, you told me these words at the'
      FROM DUAL
      UNION ALL
    SELECT 2, 'The second line.Welcome to the world of the Hackers, you told me these words at the'
    FROM DUAL
    )
SELECT LISTAGG(word, ' ') WITHIN
GROUP (
        ORDER BY w
        )
FROM (
    SELECT id,
          LEVEL AS w
        ,REGEXP_SUBSTR(s, '[^ ]+', 1, LEVEL) AS word
    FROM t CONNECT BY LEVEL <= REGEXP_COUNT(s, '[^ ]+')
   AND PRIOR id = id 
  AND PRIOR SYS_GUID() IS NOT NULL

    )
WHERE lower(word) NOT IN (
        'to'
        ,'the'
        ,'of'
        )
        GROUP BY id;

Demo