这个正则表达式(RegEx)标志是什么意思/ iD

时间:2014-02-21 16:52:32

标签: regex plsql ipv6

我想使用此正则表达式来验证IPv6,但我想了解它所做的一切 https://stackoverflow.com/a/1934546/3112803

^(?>(?>([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

但我不知道最后这个标志是什么:/iD。我知道/i标志意味着忽略大小写,但我无法找到D在任何地方所做的事情。这个答案在我认为有效的情况下得到了很多支持,但这篇帖子说没有D标志:https://stackoverflow.com/a/4415233/3112803

我试图在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

2 个答案:

答案 0 :(得分:3)

这是Regex的PCRE风格中的一面旗帜。请参阅PHP.net手册页上的注释:

http://php.net/manual/en/reference.pcre.pattern.modifiers.php(在代码示例下)

  

D(PCRE_DOLLAR_ENDONLY) -       如果设置了此修饰符,则模式中的美元元字符仅匹配于       主题字符串的结尾。如果没有这个修饰符,美元也会匹配       如果是换行符,则在最后一个字符之前       (但不是在任何其他换行之前)。此修饰符被忽略       如果设置了m修饰符。在Perl中没有与此修饰符等效的内容。

答案 1 :(得分:1)

D标志仅在PCRE中有效。以下引自PHP's documentation

  

D (PCRE_DOLLAR_ENDONLY)

     

如果设置了此修饰符,则模式中的美元元字符仅匹配主题字符串的末尾。如果没有此修饰符,如果它是换行符(但不在任何其他换行符之前),则美元也会在最终字符之前立即匹配。如果设置了m修饰符,则忽略此修饰符。在Perl中没有与此修饰符等效的内容。

摘要

PCRE风格的正则表达式符合以下格式:

  • IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334
  • 省略前导0的IPv6:2001:db8:85a3:0:0:8a2e:370:7334
  • 已删除最长连续0组的IPv6(最左边的断线):2001:db8:85a3::8a2e:370:73342001:db8::1:0:0:1
  • IPv6点分四位表示法:::ffff:192.0.2.128
  • IPv4:192.0.2.128

请注意,允许使用纯IPv4,可能是由于作者决定支持。通过删除我在下面评论过的?,可以轻松禁止它。

正则表达式根据section 2.2 of RFC 4291匹配所有有效的IPv6。但是,它不适合检查IPv6是否符合RFC 5952

建议的规范形式

模式说明

我使用术语 hexa-group 来指代以虚线十六进制表示法编写的IPv6地址中的16位组。 deci-group 指的是以点分十进制表示法写入的IPv4地址中的8位组。

^
(?>
  (?>
                                    # Below matches expanded IPv6
    ([a-f0-9]{1,4})                 # (Hexa-group) One to 4 hexadecimal digits
    (?>:(?1)){7}                    # Match 7 (: hexa-group)

    |                               # OR

                                    # Below matches shorthand notation :: IPv6
    (?!(?:.*[a-f0-9](?>:|$)){8,})   # Can't find 8 or more hexa-groups ahead
    ((?1)(?>:(?1)){0,6})?           # Match 0 to 7 hexa-groups, delimited by :
    ::                              # ::
    (?2)?                           # Match 0 to 7 hexa-groups, delimited by :
  )
  |
                                 # Below match IPv4 or IPv6 dotted-quad notation
  (?>                            
                                 # Below matches first 96-bit of IPv6
    (?>                          
                                 # Below matches expanded notation
      (?1)(?>:(?1)){5}:          # Match one hexa-group then 5 times (: hexa-group)

      |                          # OR

                                 # Below matches shorthand notation
      (?!(?:.*[a-f0-9]:){6,})    # Can't find 6 or more hexa-groups ahead
      (?3)?                      # Match 0 to 7 hexa-groups, delimited by :
      ::                         # ::
      (?>((?1)(?>:(?1)){0,4}):)? # Match 0 to 7 hexa-groups, delimited by :
    )?                           # Optional, so the regex can also match IPv4

                                 # Below matches IPv4 in dotted-decimal notation
    (25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]) # (Deci-group) One IPv4 deci-group
    (?>\.(?4)){3}                               # Match 3 (. deci-group)
  )
)
$

您可能想知道为什么我为匹配IPv6点分四元符号的简写符号的部分编写# Match 0 to 7 hexa-groups, delimited by :。这是由于通过子程序调用{​​{1}}进行模式重用。但是,正则表达式并没有错:由于较早的前瞻(?3),当您使用IPv6点分四位表示法的短手表示法时,不可能找到超过5个六进制组。

错误

顺便说一句,原始正则表达式中存在一个错误。由于第一个非回溯组(?!(?:.*[a-f0-9]:){6,})不允许回溯,它无法匹配::129.144.52.38,而与IPv6速记匹配的模式部分没有足够的检查以确保没有IPv6点缀 - 前四位表示法。简而言之:(?>pattern)可以是简写的IPv6,也可以是IPv6点分四位表示法的前缀,没有回溯引擎就无法匹配::

DEMO(注意:::129.144.52.38g标记用于测试目的)

一种快速解决方法是将第一个m更改为>。所有IPv6都应按预期正确匹配。

DEMO(注意::g标记用于测试目的)