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:7334、2001: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(注意:g 和 m 标志用于测试目的)
一种快速修复方法是将第一个 > 更改为 :。所有 IPv6 都应按预期正确匹配。
DEMO(注意:g 和 m 标志用于测试目的)