【问题标题】:IPv6 Regular Expression (RegEx) Not Working in PL/SQLIPv6 正则表达式 (RegEx) 在 PL/SQL 中不起作用
【发布时间】:2014-03-23 08:15:24
【问题描述】:

我似乎无法找出为什么这个正则表达式在 PL/SQL 中不起作用。

if ( REGEXP_LIKE(v,'/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$/iD') ) then

用于验证 IPv4 和 IPv6,来自这里:https://stackoverflow.com/a/1934546/3112803

不确定这是否与它有关,但我也问了这个关于最后 D 标志的问题:What Does This Regular Expression (RegEx) Flag Mean /iD

由于某种原因,此正则表达式适用于我在此站点上的大多数测试:http://regex101.com/ 但在PL/SQL 中,所有内容均无效。

大多数的意思是在某些情况下我发现它失败了,但我一直在寻找几天,这是我能找到的最好的发现小于 512 个字符(512 是在 PL/SQL 中使用 REGEXP_LIKE 时的限制)

如果有任何帮助,我将不胜感激。谢谢!

这些是我正在使用的测试用例...

{1: Initial address, regex should say valid/match}
select isValid('2001:0db8:0000:0000:0000:ff00:0042:8329','ipv6') from dual;

{2: After removing all leading zeroes, regex should say valid/match}
select isValid('2001:db8:0:0:0:ff00:42:8329','ipv6') from dual;

{3: After omitting consecutive sections of zeroes, regex should say valid/match}
select isValid('2001:db8::ff00:42:8329','ipv6') from dual;

{4: The loopback address, regex should say valid/match}
select isValid('0000:0000:0000:0000:0000:0000:0000:0001','ipv6') from dual;

{5: The loopback address be abbreviated to ::1 by using both rules, regex should say valid/match}
select isValid('::1','ipv6') from dual;

{6: This should be valid/match}
select isValid('ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190','ipv6') from dual;

{7: This should be valid/match}
select isValid('::','ipv6') from dual;

{8: IPv6 applications to communicate directly with IPv4 applications, regex should say valid/match}
select isValid('0:0:0:0:0:ffff:192.1.56.10','ipv6') from dual;

{9: should NOT be valid/match}
select isValid('::ffff:192.1.56.10/96','ipv6') from dual;

{old formats used for tunneling, these should NOT be valid/matches}
{10}
select isValid('0:0:0:0:0:0:192.1.56.10','ipv6') from dual;
{11}
select isValid('::192.1.56.10/96','ipv6') from dual;

{These 4 should be valid/match}
{12}
select isValid('::FFFF:129.144.52.38','ipv6') from dual;
{13}
select isValid('::129.144.52.38','ipv6') from dual;
{14}
select isValid('::FFFF:d','ipv6') from dual;
{15}
select isValid('1080:0:0:0:8:800:200C:417A','ipv6') from dual;

{These 4 should NOT be valid/match}
{16}
select isValid('::FFFF:d.d.d','ipv6') from dual;
{17}
select isValid('::FFFF:d.d','ipv6') from dual;
{18}
select isValid('::d.d.d','ipv6') from dual;
{19}
select isValid('::d.d','ipv6') from dual;

有人告诉我测试 #6 错误,ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190 不是有效的 IPv6 地址,对吗?

测试用例 8-11 来自这里:http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzai2%2Frzai2ipv6addrformat.htm,但我被告知不再使用 10&11。

【问题讨论】:

  • 不幸的是,Oracle 只支持 RegExp 语言的狭窄部分。您的正则表达式在 Oracle 中不起作用。
  • 第二次测试用例6无效。 10 和 11 也不是。
  • 是的,我知道。下面也提到了。我会更新问题,以免造成混淆。这个公认的答案是我迄今为止找到的最好的答案。但是,@nhahtdh 不同意您对第 6 项的格式的看法。

标签: regex oracle plsql ipv6


【解决方案1】:

你必须去掉开头的 / 和结尾的 /iD 这是 perl 语法的一部分,表明它是一个正则表达式。

最后的 i 开关意味着忽略大小写,可以作为 regexp_like 的额外参数给出,所以:

if ( REGEXP_LIKE(v,'^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$','i') ) the

还有更多问题,因为 perl 正则表达式不是 100% 等同于 oracle 正则表达式,我看到这里使用的模式不可用,比如?> 也许您可以在 ipv4 和 ipv6 之间拆分正则表达式,以避免达到 oracle 的限制。只需执行 REGEXP_LIKE(ip,'ipv4pattern') 或 REGEXP_LIKE(ip,'ipv6pattern')

将上述正则表达式的 ipv4 部分调整为可在 oracle 中使用的内容:

REGEXP_LIKE(ip,'^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$','i')

【讨论】:

  • 啊,谢谢,我忘记了 REGEXP_LIKE() 调用中的标志需要用逗号分隔。不幸的是,它仍然没有帮助。所有测试返回无效。我认为@EgorSkriptunoff 可能是对的。
  • 我编辑了我的帖子,在 oracle 中包含一个适用于 ipv4 部分的正则表达式。
  • 是的,我已经有一个单独的 IPv4 工作,但谢谢,我会比较你的和我的。是的,我确实希望它们分开。但几周来我一直在尝试寻找仅限 IPv6 的解决方案,但仍然找不到。这是我最初尝试找到的:stackoverflow.com/questions/21631669/…。这是我最新的测试用例:regex101.com/r/sV5cZ3。我仍然没有找到适用于PL/SQL 的仅适用于这些测试用例的 IPv6 正则表达式。
  • 我发现这篇文章提供了转换ipv6字符串的功能,也许你可以使用它们并测试它是否返回NULL stackoverflow.com/questions/6470244/…
【解决方案2】:

与其在单个正则表达式中做所有事情,不如将正则表达式分解成更小的正则表达式并测试它们:

if (
    /* IPv6 expanded */
    REGEX_LIKE(v, '\A[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}\z', 'i')
    /* IPv6 shorthand */
    OR (NOT REGEX_LIKE(v, '\A(.*?[a-f0-9](:|\z)){8}', 'i')
        AND REGEX_LIKE(v, '\A([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,6})?::([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,6})?\z', 'i'))
    /* IPv6 dotted-quad notation, expanded */
    OR REGEX_LIKE(v, '\A[a-f0-9]{1,4}(:[a-f0-9]{1,4}){5}:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z', 'i')
    /* IPv6 dotted-quad notation, shorthand */
    OR (NOT REGEX_LIKE(v, '\A(.*?[a-f0-9]:){6}', 'i')
        AND REGEX_LIKE(v, '\A([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,4})?::([a-f0-9]{1,4}:){0,5}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z', 'i'))
   ) then

这仅测试 IPv6。不允许使用 IPv4。

由于 PL/SQL 风格没有子例程调用(?n),所以别无选择,只能扩展所有内容。并且由于缺少负前瞻 (?!pattern),我们不得不使用 2 个正则表达式测试操作来模拟它。

\A\z 用于匹配字符串的开头和结尾,因为它们都不受标志的影响,并且\z 的行为与D 模式下的$ 相同PCRE。

【讨论】:

  • 干得好!注意:[a-f0-9] 可以替换为 [[:xdigit:]] 如果您对所有数字都发疯了(并且您可以省略 i 开关),这可能更具可读性
  • 这太棒了!这是迄今为止最接近的答案,我一直在寻找很长时间。我将测试用例添加到原始问题中。您的模式说数字 6 是匹配的,但有人告诉我这不是有效的 IPv6 地址?它在测试 9 和 11 中也失败了。但我不确定这些格式是否有效。我有另一篇与这篇文章非常相似的帖子,但同样适用于 ColdFusion(如果你也想要那里的积分):stackoverflow.com/questions/21631669/… 谢谢!
  • @gfrobenius:我不确定为什么 6 不是有效的 IPv6。格式方面,它不应该是错误的。测试 9 和 11 适用于 IPv6 地址前缀,而不是 IPv6 地址。
  • 感谢您使用 [[:xdigit:]] - javascript 不支持(必须将\A 换成^\z 换成@ 987654333@),但效果很好!
  • @cale_b: [[:xdigit:]] 就是[A-Fa-f0-9]
【解决方案3】:
REGEXP_LIKE(ip,'^(([\dA-F]{1,4}:([\dA-F]{1,4}:([\dA-F]{1,4}:([\dA-F]{1,4}:([\dA-F]{1,4}:[\dA-F]{0,4}|:[\dA-F]{1,4})?|(:[\dA-F]{1,4}){0,2})|(:[\dA-F]{1,4}){0,3})|(:[\dA-F]{1,4}){0,4})|:(:[\dA-F]{1,4}){0,5})((:[\dA-F]{1,4}){2}|:(25[0-5]|(2[0-4]|1\d|[1-9])?\d)(\.(25[0-5]|(2[0-4]|1\d|[1-9])?\d)){3})|(([\dA-F]{1,4}:){1,6}|:):[\dA-F]{0,4}|([\dA-F]{1,4}:){7}:)\z', 'i')

http://home.deds.nl/~aeron/regex/ 的 XML 正则表达式修改

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-27
    • 2014-03-05
    • 1970-01-01
    • 2019-06-10
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    相关资源
    最近更新 更多