【问题标题】:Replace characters after a defined pattern with regexp_replace in oracle在 oracle 中用 regexp_replace 替换已定义模式后的字符
【发布时间】:2017-09-17 01:11:05
【问题描述】:

我想用 oracle 中的函数 regexp_replace 替换字符串中的单个字符。字符串中的替换应该在定义的模式之后开始。

示例:

在字符串“Heyho || HeyheyHo”中,我将替换模式“||”后面的所有“y”字符与字符“我”。出现在模式之前的字符应该被忽略。

字符串:

Heyho || HeyheyHo

替换后的字符串:

Heyho || HeiheiHo

对你来说肯定很容易吗?

【问题讨论】:

  • 字符串中总是有一个||?或者可能是多次?

标签: oracle regexp-replace


【解决方案1】:

这是一个使用 regexp_replace 的解决方案。第 4 个参数是起始位置。经过一番思考,我决定不跳过“+2”。不要偷懒,浪费循环测试你知道不是目标角色的角色。

SQL> with tbl(str) as (
     select 'Heyho || HeyheyHo' from dual
   )
   select str before,
          regexp_replace(str, 'y', 'i', instr(str, '||')+2) after
   from tbl;

BEFORE            AFTER
----------------- -----------------
Heyho || HeyheyHo Heyho || HeiheiHo

SQL>

【讨论】:

  • 谢谢加里。这个解决方案是我基本想要的,下次我最好研究一下语法。
  • 我很好奇你为什么不选择 Aleksej 被证明更快的方法?
【解决方案2】:

你不需要正则表达式;您可以使用INSTRSUBSTRREPLACE 来满足您的需求:

with test(s) as (
        select 'Heyho || HeyheyHo' from dual
    )
    /* the query */
    select s as input,
           substr(s, 1, instr(s, '||')+1) || 
           replace( substr(s, instr(s, '||')+2), 'y', 'i') as result
    from test

给予:

INPUT             RESULT
----------------- --------------------
Heyho || HeyheyHo Heyho || HeiheiHo

它是如何工作的:

select s as input,
       substr(s, 1, instr(s, '||')+1) beforeDelimiter,
       substr(s, instr(s, '||')+2)   afterDelimiter,
       replace( substr(s, instr(s, '||')+2), 'y', 'i') afterDelimiterEdited,
       substr(s, 1, instr(s, '||')+1) || 
       replace( substr(s, instr(s, '||')+2), 'y', 'i') as result
from test

给予:

INPUT             BEFOREDELI AFTERDELIM AFTERDELIM RESULT
----------------- ---------- ---------- ---------- --------------------
Heyho || HeyheyHo Heyho ||    HeyheyHo   HeiheiHo  Heyho || HeiheiHo

如果字符串中出现多个||replace 将在第一次出现后修改字符。

根据 Mathguy 的评论,我不能说这个解决方案比正则表达式更快。

正则表达式的解决方案可能是:

select regexp_replace(s, 'y', 'i', instr(s, '||') ) as result

以下是对使用相同数据(500 万行)以相同方式创建的 2 个表进行的小型性能测试:

SQL> create table testA3(s) as
  2  select regexp_replace(s, 'y', 'i', instr(s, '||') ) as result
  3  from testA;

Table created.

Elapsed: 00:00:30.75
SQL> create table testB3(s) as
  2  select substr(s, 1, instr(s, '||')+1) ||
  3             replace( substr(s, instr(s, '||')+2), 'y', 'i') as result
  4  from testB;

Table created.

Elapsed: 00:00:14.82

这里的标准方法似乎更快;使用 3M 行的相同测试,正则表达式方法耗时 18 秒,标准方法耗时 7 秒。

测试当然不是详尽无遗的,结果可能会因许多事情而改变,但即使在这种情况下,也需要考虑标准方式作为正则表达式的一个很好的替代方法,在这种情况下需要许多标准操作才能获得相同的结果正则表达式的结果。

这是 3M 行的完整测试;我做了一个CREATE 和 2 个INSERTs 以避免CONNECT BY 的内存问题,级别非常高。

此外,在 3M 和 5M 行测试之间,我删除了表并再次创建它们,以确保缓存不会影响结果。

SQL> create table testA(s) as
  2  select 'Heyho || HeyheyHo' || level || 'HeyheyHo'
  3  from dual
  4  connect by level <= 1000000;

Table created.

SQL> create table testB(s) as
  2  select 'Heyho || HeyheyHo' || level || 'HeyheyHo'
  3  from dual
  4  connect by level <= 1000000;

Table created.

SQL> insert into testB(s)
  2  select 'Heyho || HeyheyHo' || to_char(level + 1000000) || 'HeyheyHo'
  3  from dual
  4  connect by level <= 1000000;

1000000 rows created.

SQL> insert into testA(s)
  2  select 'Heyho || HeyheyHo' || to_char(level + 1000000)  || 'HeyheyHo'
  3  from dual
  4  connect by level <= 1000000;

1000000 rows created.

SQL> insert into testB(s)
  2  select 'Heyho || HeyheyHo' || to_char(level + 2000000)  || 'HeyheyHo'
  3  from dual
  4  connect by level <= 1000000;

1000000 rows created.

SQL> insert into testA(s)
  2  select 'Heyho || HeyheyHo' || to_char(level + 2000000)  || 'HeyheyHo'
  3  from dual
  4  connect by level <= 1000000;

1000000 rows created.

SQL> select count(1), count(distinct s) from testA;

  COUNT(1) COUNT(DISTINCTS)
---------- ----------------
   3000000          3000000

SQL> select count(1), count(distinct s) from testB;

  COUNT(1) COUNT(DISTINCTS)
---------- ----------------
   3000000          3000000

SQL> set timing on
SQL> create table testA2(s) as
  2  select regexp_replace(s, 'y', 'i', instr(s, '||')+2 ) as result
  3  from testA;

Table created.

Elapsed: 00:00:17.66
SQL> create table testB2(s) as
  2  select substr(s, 1, instr(s, '||')+1) ||
  3             replace( substr(s, instr(s, '||')+2), 'y', 'i') as result
  4  from testB;

Table created.

Elapsed: 00:00:06.96
SQL>

【讨论】:

  • 非常感谢 Aleksej 快速而成功的回复
  • 在大多数情况下,使用标准(非正则表达式)函数可以加快执行速度。然而,在这个例子中,我计算了每行六个字符串函数:两个instr、两个substr、一个replace 和一个连接。在这种情况下,使用正则表达式的解决方案可能会更快——使用一个instr 和一个regexp_replace。标准函数更快,但不是快五倍。
  • @mathguy 老实说,我低估了这么多标准函数可能导致解决方案速度变慢的事实。我刚刚做了(并发布)了一个小测试来检查它是如何进行的,似乎标准方法仍然比正则表达式更快。这只是对单个实例的单个测试,但是 ...
  • 整洁!感谢您发布性能比较。如果您也发布语句以创建测试表,这将有所帮助(如果不是太麻烦的话)。无论如何,赞成额外的工作。 (或者……等等……同样的数据,你的意思是你复制了相同的输入字符串 500 万次?)
  • @mathguy 正确的怀疑;我创建了具有 3M 不同行的表。刚刚发布了 3M 行的完整测试
猜你喜欢
  • 2017-12-07
  • 2017-02-26
  • 2021-12-29
  • 2012-09-25
  • 2015-03-12
  • 2015-08-09
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
相关资源
最近更新 更多