【问题标题】:regexp replace to replace the second special character from the last in a string正则表达式替换以替换字符串中最后一个特殊字符的第二个特殊字符
【发布时间】:2019-12-07 03:45:34
【问题描述】:

我必须替换字符串中的最后 2 个特殊字符。我尝试了以下选项

它替换了我的字符串中的最后一个特殊字符

select regexp_replace(trim('Clifton/RosalieBolner''49-S.R.'),'([^0-9A-Za-z]+)$','') from dual;

它替换了我的字符串中的所有特殊字符

select regexp_replace(trim('Clifton/RosalieBolner''49-S.R.'),'[^0-9A-Za-z]','') from dual;

我需要一个只替换字符串中最后两个特殊字符的函数。

e.g 1 Clifton/RosalieBolner''49-S.R.      should be 
      Clifton/RosalieBolner''49-SR  

e.g 2 Hydroworx-Hydrotherapy-Hydrotr      should be 
      HydroworxHydrotherapyHydrotr   

e.g 3 Lenore&BillAlexander'35/Faulk       should be 
      Lenore&BillAlexander35Faulk

【问题讨论】:

  • 你应该解释你正在寻找的逻辑。为什么在第一个字符串-没有被替换,而是在第二个
  • 在第一个示例中,最后 2 个特殊字符是点。所以只有那些 2 必须被删除。在第二个中最后 2 个特殊字符是 - 并且那些 2 被删除

标签: sql oracle


【解决方案1】:

这个怎么样?查看代码中的 cmets:

SQL> with test (col) as
  2    (select 'Clifton/RosalieBolner''49-S.R.' from dual union all
  3     select 'Hydroworx-Hydrotherapy-Hydrotr' from dual union all
  4     select 'Lenore&BillAlexander''35/Faulk' from dual union all
  5     select 'This-is#just)an_example'        from dual
  6    )
  7  select
  8    col,
  9    regexp_replace
 10      (col,
 11       '[^[:alnum:]]',                 -- replace non alphanumeric ...
 12       '',                             -- .. with an empty string
 13       -- starting at position calculated as position of ...
 14       regexp_instr(col,
 15                    '[^[:alnum:]]',    -- ... a non alphanumeric character
 16                    1,                 -- found from the beginning of the string
 17                    -- taking into account the last and previous to last occurence
 18                    -- calculated by regexp_count which finds number of non alphanumerics
 19                    greatest(regexp_count(col, '[^[:alnum:]]') - 1, 1)),
 20       0) result
 21  from test;

COL                            RESULT
------------------------------ ----------------------------------------
Clifton/RosalieBolner'49-S.R.  Clifton/RosalieBolner'49-SR
Hydroworx-Hydrotherapy-Hydrotr HydroworxHydrotherapyHydrotr
Lenore&BillAlexander'35/Faulk  Lenore&BillAlexander35Faulk
This-is#just)an_example        This-is#justanexample

SQL>

【讨论】:

  • 谢谢。将在我的 plsql 块中尝试此选项以及 REVERSE
  • 不客气。请注意:REVERSE 未记录在案,Oracle 可能会将其从任何未来的数据库版本中删除,因此您的代码将无法工作。此外,它反转字节,而不是字符,它在多字节字符集中无法正常工作。
  • 考虑到很多公司需要很长时间才能切换到新版本并且oracle仍然没有删除该功能,我会说没有风险没有乐趣:) 10年后你仍然可以改变它,但是什么会在这么多年后发生,谁知道呢。但你应该采取最优化的方案。
  • 好吧,@hotfix,WM_CONCAT 也是如此。它没有记录,但它有效。 Oracle 从 12c 开始将其删除(确实,将其替换为“官方”并记录在案的 LISTAGG)。 REVERSE 也可能发生同样的情况——Oracle 将删除它并提供替代品,但开发人员(使用 REVERSE)将不得不修复他们的代码。但是,是的 - 如果有人永远留在 11g 上,不用担心(除了功能的限制)。
【解决方案2】:

也许这个问题有更好的解决方案,但这个可行

with str as(
select 'Clifton/RosalieBolner''49-S.R.' as txt from dual union all
select 'Hydroworx-Hydrotherapy-Hydrotr' as txt from dual union all
select 'Lenore&BillAlexander''35/Faulk' as txt from dual 
)
select REVERSE(regexp_replace(regexp_replace(REVERSE(t.txt),'[^A-Za-z0-9]','',1,1),'[^A-Za-z0-9]','',1,1)) as new_str
from str t;

首先使用反向函数,然后删除第一次出现两次,然后再次反向

文本 | REVERSE_TXT | NEW_STR :----------------------------- | :----------------------------- | :---------------------------- 克利夫顿/罗莎莉博尔纳'49-S.R. | .R.S-94'renloBeilasoR/notfilC |克利夫顿/罗莎莉博尔纳'49-SR Hydroworx-水疗-Hydrotr | rtordyH-yparehtordyH-xrowordyH | HydroworxHydrotherapyHydrotr Lenore&BillAlexander'35/福克 | kluaF/53'rednaxelAlliB&eroneL | Lenore&Bill 亚历山大35福克

db小提琴here

【讨论】:

  • 谢谢。但我仍然认为我们可以在没有逆转的情况下实现这一目标。
  • select regexp_replace(trim('Hydroworx Hydrotherapy Hydrotr'),' ([^ ]+) ([^ ]+)$', '\1\2') from dual;此语法从字符串中删除了最后 2 个空格。这对特殊字符不起作用。
  • 那是作弊 :),使用未记录的函数!
  • @Littlefoot 没有欺骗没有生命 :)
【解决方案3】:

这是另一种看待它的方式。使用 REGEXP_REPLACE() 对字符串的不同部分进行分组,然后只显示您想要的组。在这里,正则表达式专门将最后 2 个非字母数字字符与之前、之后或之间的任何字符的可选字符串组合在一起,但它们出现在字符串的末尾。将所有这些替换为第 1、3 和 5 组,除了 2 个非字母数字字符。

with test(id, col) as (
  select 1, 'Clifton/RosalieBolner''49-S.R.' from dual union all
  select 2, 'Hydroworx-Hydrotherapy-Hydrotr' from dual union all
  select 3, 'Lenore&BillAlexander''35/Faulk' from dual union all
  select 4, 'This-is#just)an_example'        from dual union all
  select 5, 'Test line 5 special *chars'     from dual union all
  select 6, 'TTest line 6^char'              from dual union all
  select 7, 'Thislineisoneword'              from dual union all
  select 8, '^^Thislineisonewordtoo'         from dual union all  
  select 9, NULL                             from dual
)
select id, col before,
  regexp_replace(col, '^(.*)?([^[:alnum:]])(.*)?([^[:alnum:]])(.*)?$', '\1\3\5') after
from test
order by id;


        ID BEFORE                         AFTER                         
---------- ------------------------------ ------------------------------
         1 Clifton/RosalieBolner'49-S.R.  Clifton/RosalieBolner'49-SR   
         2 Hydroworx-Hydrotherapy-Hydrotr HydroworxHydrotherapyHydrotr  
         3 Lenore&BillAlexander'35/Faulk  Lenore&BillAlexander35Faulk   
         4 This-is#just)an_example        This-is#justanexample         
         5 Test line 5 special *chars     Test line 5 specialchars      
         6 TTest line 6^char              TTest line6char               
         7 Thislineisoneword              Thislineisoneword             
         8 ^^Thislineisonewordtoo         Thislineisonewordtoo          
         9                                                              

9 rows selected.

【讨论】:

  • 感谢您的回复和详细解释。如果我想保留撇号以及字母数字。我怎么把它包括在内?
  • 它已经做到了。被删除的第 2 组和第 4 组是单个非字母数字字符。如果我遗漏了什么,请使用之前/之后的示例进行更新以澄清。
  • 在第三个示例中,我想保留撇号并删除与号。就像从 Lenore&BillAlexander'35/Faulk 到 LenoreBillAlexander'35Faulk
【解决方案4】:

为什么不使用反向引用?更多信息可以在REGEXP_REPLACE函数的页面上找到。
SELECT 语句的CROSS APPLY 子句用于将cleansed_s“变量”的计算移动到JOIN 区域,并且只指定一次。
REGEXP_REPLACE 函数的 match_parameter 参数中的 x 允许您忽略模式中的空白字符。
使用alternative quoting mechanism for string literals 将空格字符包含在模式中以提高可读性。但是,鉴于 Oracle 支持 some commonly used PERL regular expression operators,可以更简单地编写 REGEXP_REPLACE 函数的调用:regexp_replace(s, '(\W(\w*))?\W(\w*)$', '\2\3')

with
  t as(
    select
      'Clifton/RosalieBolner''49-S.R.' as s,
      'Clifton/RosalieBolner''49-SR' as expected_result
    from dual union all
    select
       'Hydroworx-Hydrotherapy-Hydrotr',
       'HydroworxHydrotherapyHydrotr'
    from dual union all
    select
      'Lenore&BillAlexander''35/Faulk',
      'Lenore&BillAlexander35Faulk'
    from dual union all
    select 'foo', 'foo' from dual union all
    select 'foo&bar', 'foobar' from dual union all
    select '..', '' from dual
)
select
  t.*,
  ca.*,
  case
    when t.expected_result is null or
         t.expected_result = ca.cleansed_s then 'passed'
    else 'not passed'
  end as test_result
from t
cross apply (
  select regexp_replace(s,
           q'% ([^[:alnum:]]([[:alnum:]]*))?
               [^[:alnum:]]([[:alnum:]]*)$ %',
           '\2\3', 1, 0, 'x') as cleansed_s from dual
) ca;

结果:

+--------------------------------+------------------------------+------------------------------+-------------+
|               S                |       EXPECTED_RESULT        |          CLEANSED_S          | TEST_RESULT |
+--------------------------------+------------------------------+------------------------------+-------------+
| Clifton/RosalieBolner'49-S.R.  | Clifton/RosalieBolner'49-SR  | Clifton/RosalieBolner'49-SR  | passed      |
| Hydroworx-Hydrotherapy-Hydrotr | HydroworxHydrotherapyHydrotr | HydroworxHydrotherapyHydrotr | passed      |
| Lenore&BillAlexander'35/Faulk  | Lenore&BillAlexander35Faulk  | Lenore&BillAlexander35Faulk  | passed      |
| foo                            | foo                          | foo                          | passed      |
| foo&bar                        | foobar                       | foobar                       | passed      |
| ..                             |                              |                              | passed      |
+--------------------------------+------------------------------+------------------------------+-------------+

Demo.

【讨论】:

    猜你喜欢
    • 2014-05-05
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    相关资源
    最近更新 更多