【问题标题】:Oracle - why do none of the provided regexs work?Oracle - 为什么提供的正则表达式都不起作用?
【发布时间】:2021-06-19 19:34:34
【问题描述】:

我尝试了来自here 的多个正则表达式,但它们都不能正常工作。示例:

declare
  v_result integer;
  v_link nvarchar2(300) := 'http://example.com/blah_blah/';
  v_regexp nvarchar2(300) := '@^(https?|ftp)://[^\s/$.?#].[^\s]*$@iS';
begin
  begin
    select 1 into v_result
    from dual
    where regexp_like(v_link, v_regexp);
  exception when no_data_found then
      dbms_output.put_line('false');
      return;
  end;
  dbms_output.put_line('true');
end;

这将返回 false,尽管它应该返回 true。为什么?

【问题讨论】:

  • 这些正则表达式都不会在 Oracle 中工作,因为它们不使用与 Oracle 相同的正则表达式语法。

标签: regex oracle plsql


【解决方案1】:

Oracle 中的正则表达式不支持:

  • 正则表达式前缀字符(您链接的页面上的许多示例都以@#~_ 开头)。同样,Oracle 也不支持将相同字符作为后缀。这些似乎特定于某些解析器/语言,不是标准的正则表达式语法。
  • 嵌入在正则表达式开头或结尾的标志(即不区分大小写)(许多示例以@iS 结尾或以(?i) 开头)。这需要作为参数传递给您正在使用的正则表达式匹配函数,而不是嵌入到正则表达式字符串中。
  • 字符集匹配中的类 Perl 模式(在 Oracle 中,[^\s] 将匹配任何不是 \s 的字符,当意图是匹配任何不是由 Perl 匹配的空格字符时-style \s 表达式;这需要转换为 POSIX 表达式 [^[:space:]])。
  • 非捕获组(Oracle 不支持(?: ),需要转换为捕获组( ))。
  • 字边界(Oracle 不支持\b。没有可以使用的替代语法;您只需从正则表达式中删除这些)。
  • 向前看(Oracle 不支持(?= )。同样,这种语法没有替代品;您要么需要找到不带向前看的等效结构,要么不能使用依赖于此的正则表达式)。李>
  • 在字符集匹配中转义了-] 字符。 (在 Oracle 中,您需要使用 []a-z-],其中 ] 字符作为字符集中的第一个字符,- 作为字符集中的最后一个字符,而不是使用 [a-z\-\]],其中 \ 是用于转义这些字符)。

可能还有更多不支持的内容,但您需要更正所有这些问题才能修复正则表达式。

【讨论】:

  • Word boundaries ... There is no replacement syntax ...也许是这样,但我们可以使用(^| )some_word( |$)接近
  • @TimBiegeleisen \b 寻找更多内容(包括标点符号、方括号、其他空格等),而且当您的替换不是时,它是零宽度匹配。此外,其中一些正则表达式的 \b 散布在整个表达式中(至少有人使用它来匹配 TLD 的结尾),并且在这些点上查找 ( |$) 会给正则表达式带来完全不同的含义。
【解决方案2】:

您的正则表达式模式似乎取自一些需要在模式中使用正式分隔符的来源。这在 Oracle 中不是必需的,实际上您的前导/尾随 @ 将匹配此文字字符。此外,如果您想在不区分大小写模式下使用REGEXP_LIKE,则应将'i' 作为第三个参数标志传递,而不是使用附加到模式末尾的@i

还要注意模式本身有问题。您可能希望第一个字符类是 +,一个或多个。而且,分隔域和结尾的文字点需要用反斜杠转义。最后,如果你想在一个字符类中表示空格inside,你应该使用[:space:],而不是\s,后者将被解释为文字字符s。考虑到所有这些,考虑这个版本:

SELECT *
FROM yourTable
WHERE REGEXP_LIKE(url, '^(https?|ftp)://[^[:space:]/$.?#]+\.[^[:space:]]*$', 'i');

数据:

WITH yourTable AS (
    SELECT 'http://example.com/blah_blah/' AS url FROM dual UNION ALL
    SELECT 'http://test.com' FROM dual
)

Demo

【讨论】:

  • 删除分隔符解决了一些问题。但是,无论是否添加了您的修改(+ 和 \),https://www.example.com 都会返回 true,但如果将“example”替换为其他随机词,例如“test”或“something”,则会返回 false。 [^..] 不是要排除括号中的字符吗?
  • @vr552 很好,我想你想在你的角色类中使用[:space:],而不是\s。检查更新,它现在与 test URL 匹配(之前不匹配,因为域名中包含 s)。
猜你喜欢
  • 2015-04-13
  • 2014-06-01
  • 1970-01-01
  • 2012-11-17
  • 2013-12-05
  • 2014-12-03
相关资源
最近更新 更多