与有效的IPv6地址匹配的正则表达式

时间:2020-03-05 18:50:33  来源:igfitidea点击:

我在编写匹配有效IPv6地址的正则表达式时遇到了麻烦,包括压缩格式的地址(每个字节对中都带有::或者前导零)。

有人可以建议一个满足要求的正则表达式吗?

我正在考虑扩展每个字节对,并使用更简单的正则表达式匹配结果。

解决方案

回答

来自" IPv6正则表达式":

(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}\Z)|
(\A([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}\Z)|
(\A([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}\Z)|
(\A(([0-9a-f]{1,4}:){1,7}|:):\Z)|
(\A:(:[0-9a-f]{1,4}){1,7}\Z)|
(\A((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A:(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)

回答

如果我可以避开问题,请考虑使用网络库的地址概念来解析和检查错误。

我想在某个时候我们会想对这些地址做些什么,那么为什么不直接进入源代码并确保网络库能够理解该地址呢?这比仅希望将要在此处发布的任何正则表达式要匹配实现的地址概念更好。

在Java中,我们有InetAddress。在.NET中,我们有IPAddress。在.NET中,我们甚至可以在IPAddress类上使用TryParse来为我们执行此测试!

bool IsIP6(string addr) {
    IPAddress ip;
    if (IPAddress.TryParse(addr, out ip)) {
        return ip.AddressFamily == AddressFamily.InterNetworkV6;
    }
    else {
        return false;
    }
}

回答

我必须坚决支持弗兰克·克鲁格的回答。

虽然我们说我们需要一个正则表达式来匹配IPv6地址,但是我假设我们真正需要的是能够检查给定的字符串是否为有效的IPv6地址。这里有一个微妙但重要的区别。

有多种方法可以检查给定字符串是否为有效的IPv6地址,而正则表达式匹配只是一种解决方案。

如果可以,请使用现有的库。该库将具有较少的错误,并且其使用将减少需要维护的代码。

Factor Mystic建议的正则表达式长而复杂。它最有可能起作用,但是我们还应该考虑如果它意外失败该如何应对。我要在此处说明的要点是,如果我们自己无法形成所需的正则表达式,则将无法轻松调试它。

如果没有合适的库,最好编写自己的不依赖于正则表达式的IPv6验证例程。如果我们编写它,则说明我们理解它;如果我们理解,则可以添加注释以对其进行解释,以便其他人也可以理解并随后对其进行维护。

使用正则表达式时,请谨慎行事,我们无法向他人解释其功能。

回答

如果我们使用Perl,请尝试使用Net :: IPv6Addr

use Net::IPv6Addr;

if( defined Net::IPv6Addr::is_ipv6($ip_address) ){
  print "Looks like an ipv6 address\n";
}

NetAddr :: IP

use NetAddr::IP;

my $obj = NetAddr::IP->new6($ip_address);

验证:: IP

use Validate::IP qw'is_ipv6';

if( is_ipv6($ip_address) ){
  print "Looks like an ipv6 address\n";
}

回答

听起来我们可能正在使用Python。如果是这样,我们可以使用以下方式:

import socket

def check_ipv6(n):
    try:
        socket.inet_pton(socket.AF_INET6, n)
        return True
    except socket.error:
        return False

print check_ipv6('::1') # True
print check_ipv6('foo') # False
print check_ipv6(5)     # TypeError exception
print check_ipv6(None)  # TypeError exception

我不认为我们必须将IPv6编译到Python中才能获得" inet_pton",如果我们将" socket.AF_INET"作为第一个参数传递,它也可以解析IPv4地址。注意:这可能不适用于非Unix系统。

回答

正则表达式允许在IPv4部分中使用前导零。

一些Unix和Mac发行版将这些段转换为八进制。

我建议将25 [0-5] | 2 [0-4] \ d | 1 \ d \ d | [1-9]?\ d用作IPv4段。

回答

以下将验证IPv4,IPv6(完整和压缩)和IPv6v4(完整和压缩)地址:

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

回答

在Java中,我们可以使用库类sun.net.util.IPAddressUtil

IPAddressUtil.isIPv6LiteralAddress(iPaddress);