【问题标题】:What Does This Regular Expression (RegEx) Flag Mean /iD这个正则表达式 (RegEx) 标志是什么意思 /iD
【发布时间】:2014-03-23 07:36:23
【问题描述】:

我想使用这个正则表达式来验证 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

【问题讨论】:

  • 指定您使用的语言(正则表达式的“风格”)。 Perl 有它的标志集,PHP 也有,PHP 和 preg (PCRE) 也有。
  • @PhilPerry 我用该信息更新问题。我不想改变整个问题。这只是为了找出该标志的含义。我会做一个单独的问题,为什么这在 PL/SQL 中不起作用。

标签: regex plsql ipv6


【解决方案1】:

这是正则表达式 PCRE 风格的标志。请参阅 PHP.net 手册页上的注释:

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

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

【讨论】:

  • There is no equivalent to this modifier in Perl. PCRE 中“Perl 兼容”的另一个例子是不真实的。
  • 有趣...每天都学习新东西。
  • 我不关心 PHPPerl 这个问题,但我很感激这些信息。我现在正在尝试在PL/SQL 中进行 IPv6 验证。所以我猜这个标志不适用于PL/SQL,对吗?
  • @gfrobenius 根据regular-expressions.info oracle 只支持i,c,n,m,x
【解决方案2】:

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)
  )
)
$

您可能想知道为什么我写# Match 0 to 7 hexa-groups, delimited by : 用于匹配 IPv6 点分四组符号的速记符号的部分。这是由于通过子例程调用(?3) 重用模式。但是,正则表达式并没有错:由于之前的前瞻 (?!(?:.*[a-f0-9]:){6,}),当您匹配 IPv6 点分四进制表示法的速记表示法时,不可能找到超过 5 个六进制组。

错误

顺便说一句,原来的正则表达式有一个错误。由于第一个非回溯组(?>pattern) 不允许回溯,它无法匹配::129.144.52.38,而匹配IPv6 速记的模式部分没有足够的检查来确保前面没有IPv6 点分四符号。简而言之::: 可以是 IPv6 的简写,也可以是 IPv6 点分四方符号的前缀,如果不回溯,引擎将无法匹配 ::129.144.52.38

DEMO(注意:gm 标志用于测试目的)

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

DEMO(注意:gm 标志用于测试目的)

【讨论】:

  • 谢谢,不幸的是它不适用于我的所有测试用例,在PL/SQL 中根本不起作用。一段时间以来,我一直在尝试寻找 仅 IPv6 解决方案,但仍然找不到。这是我最初尝试找到的:stackoverflow.com/questions/21631669/…。这是我最新的测试用例:regex101.com/r/sV5cZ3。你的不适用于一些测试。我开始认为我的测试用例无效。这个问题更重要的是弄清楚/D 标志。上面的链接用于寻找模式。
  • @gfrobenius:代码甚至不是我的。它与您从另一个问题中获得的任何内容相同。
  • @gfrobenius:实际上,原始正则表达式中存在一个小错误,但您不应该担心,因为您正在寻找的是在 PL/SQL 中工作的正则表达式
  • @gfrobenius:顺便说一句,原始正则表达式正在测试整个字符串是否仅包含 IPv6。如果要测试由换行符分隔的多个字符串,则需要 gm 标志。 regex101.com/r/jD2zD6
  • 非常感谢。我为您提供了与此主题相关的其他问题的答案,这个问题更多的是/D 和@SmokeyPHP 首先回答了这个问题。
猜你喜欢
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-17
  • 2021-05-20
相关资源
最近更新 更多