代码之家  ›  专栏  ›  技术社区  ›  Joe Holloway

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

  •  112
  • Joe Holloway  · 技术社区  · 16 年前

    我在编写与有效的IPv6地址匹配的正则表达式时遇到问题,包括那些压缩格式的地址(使用 :: 或从每个字节对中省略前导零)。

    有人能推荐一个满足要求的正则表达式吗?

    我正在考虑扩展每个字节对,并用一个更简单的regex来匹配结果。

    31 回复  |  直到 6 年前
        1
  •  -1
  •   Frank Krueger    16 年前

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

    我想在某个时候你会想对这些地址做些什么,那么为什么不直接去源代码处,确保你的网络库能够理解这个地址呢?这比仅仅希望这里发布的任何regex都符合您的实现的地址概念要好。

    在爪哇,我们有 InetAddress . 在.NET中,我们有 IPAddress . 在.NET中,您甚至 TryParse on the IPAddress class 为你做这个测试!

    bool IsIP6(string addr) {
        IPAddress ip;
        if (IPAddress.TryParse(addr, out ip)) {
            return ip.AddressFamily == AddressFamily.InterNetworkV6;
        }
        else {
            return false;
        }
    }
    
        2
  •  213
  •   Qix - MONICA WAS MISTREATED    7 年前

    我无法得到@factor mystic使用posix正则表达式的答案,所以我编写了一个可以使用posix正则表达式和perl正则表达式的答案。

    它应该匹配:

    IPv6正则表达式:

    (([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))
    

    为了便于阅读,下面是上面的正则表达式,将主表达式或点拆分为单独的行:

    # IPv6 RegEx
    (
    ([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|          # 1:2:3:4:5:6:7:8
    ([0-9a-fA-F]{1,4}:){1,7}:|                         # 1::                              1:2:3:4:5:6:7::
    ([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|         # 1::8             1:2:3:4:5:6::8  1:2:3:4:5:6::8
    ([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|  # 1::7:8           1:2:3:4:5::7:8  1:2:3:4:5::8
    ([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|  # 1::6:7:8         1:2:3:4::6:7:8  1:2:3:4::8
    ([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|  # 1::5:6:7:8       1:2:3::5:6:7:8  1:2:3::8
    ([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|  # 1::4:5:6:7:8     1:2::4:5:6:7:8  1:2::8
    [0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|       # 1::3:4:5:6:7:8   1::3:4:5:6:7:8  1::8  
    :((:[0-9a-fA-F]{1,4}){1,7}|:)|                     # ::2:3:4:5:6:7:8  ::2:3:4:5:6:7:8 ::8       ::     
    fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|     # fe80::7:8%eth0   fe80::7:8%1     (link-local IPv6 addresses with zone index)
    ::(ffff(:0{1,4}){0,1}:){0,1}
    ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
    (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|          # ::255.255.255.255   ::ffff:255.255.255.255  ::ffff:0:255.255.255.255  (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
    ([0-9a-fA-F]{1,4}:){1,4}:
    ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
    (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])           # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
    )
    
    # IPv4 RegEx
    ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])
    

    为了使上述内容更容易理解,以下“伪”代码复制了上述内容:

    IPV4SEG  = (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])
    IPV4ADDR = (IPV4SEG\.){3,3}IPV4SEG
    IPV6SEG  = [0-9a-fA-F]{1,4}
    IPV6ADDR = (
               (IPV6SEG:){7,7}IPV6SEG|                # 1:2:3:4:5:6:7:8
               (IPV6SEG:){1,7}:|                      # 1::                                 1:2:3:4:5:6:7::
               (IPV6SEG:){1,6}:IPV6SEG|               # 1::8               1:2:3:4:5:6::8   1:2:3:4:5:6::8
               (IPV6SEG:){1,5}(:IPV6SEG){1,2}|        # 1::7:8             1:2:3:4:5::7:8   1:2:3:4:5::8
               (IPV6SEG:){1,4}(:IPV6SEG){1,3}|        # 1::6:7:8           1:2:3:4::6:7:8   1:2:3:4::8
               (IPV6SEG:){1,3}(:IPV6SEG){1,4}|        # 1::5:6:7:8         1:2:3::5:6:7:8   1:2:3::8
               (IPV6SEG:){1,2}(:IPV6SEG){1,5}|        # 1::4:5:6:7:8       1:2::4:5:6:7:8   1:2::8
               IPV6SEG:((:IPV6SEG){1,6})|             # 1::3:4:5:6:7:8     1::3:4:5:6:7:8   1::8
               :((:IPV6SEG){1,7}|:)|                  # ::2:3:4:5:6:7:8    ::2:3:4:5:6:7:8  ::8       ::       
               fe80:(:IPV6SEG){0,4}%[0-9a-zA-Z]{1,}|  # fe80::7:8%eth0     fe80::7:8%1  (link-local IPv6 addresses with zone index)
               ::(ffff(:0{1,4}){0,1}:){0,1}IPV4ADDR|  # ::255.255.255.255  ::ffff:255.255.255.255  ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
               (IPV6SEG:){1,4}:IPV4ADDR               # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
               )
    

    我在Github上发布了一个测试正则表达式的脚本: https://gist.github.com/syzdek/6086792

        3
  •  49
  •   community wiki 14 revs MichaelRushton    12 年前

    以下内容将验证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'
    
        4
  •  23
  •   the Tin Man    8 年前

    从“ IPv6 regex “:

    (\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)
    
        5
  •  19
  •   the Tin Man    8 年前

    听起来您可能在使用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 ,如果传入,还可以解析IPv4地址 socket.AF_INET 作为第一个参数。注意:这可能不适用于非UNIX系统。

        6
  •  8
  •   Jon Cram    16 年前

    我必须坚决支持 Frank Krueger .

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

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

    如果可以,请使用现有库。这个库将有更少的错误,并且它的使用将导致更少的代码供您维护。

    正则表达式由 Factor Mystic 长而复杂。它最有可能起作用,但是你也应该考虑如果它意外地失败了你将如何应对。我在这里要说明的一点是,如果你不能自己形成一个必需的正则表达式,你就不能很容易地调试它。

    如果没有合适的库,最好编写自己的不依赖正则表达式的IPv6验证例程。如果你写了它,你就会理解它,如果你理解了它,你可以添加注释来解释它,这样其他人也可以理解它,并随后对它进行维护。

    使用不能向其他人解释其功能的正则表达式时,请小心操作。

        7
  •  7
  •   Remi Morin    11 年前

    我不是ipv6专家,但我认为您可以更轻松地获得非常好的结果:

    ^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$
    

    回答“是一个有效的ipv6”,我觉得没问题。把它分成几部分…算了吧。我省略了未指定的地址(::),因为在我的数据库中没有“未指定地址”的用处。

    开始: ^([0-9A-Fa-f]{0,4}:){2,7} <--匹配可压缩部分,我们可以将其翻译为:在2到7个冒号之间,它们之间可能有heaxadecimal数字。

    然后: [0-9A-Fa-f]{1,4}$ <--十六进制数(省略前导0) 或 ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4} <--IPv4地址

        8
  •  7
  •   Egor    11 年前

    此正则表达式将根据正则表达式的GEU C++实现与有效的IPv6和IPv4地址相匹配,并使用常规扩展模式:

    "^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(%.+)?\s*$"
    
        9
  •  4
  •   user2623580    11 年前

    当心! 在Java中,使用iNETAdvor和相关类(iNET4Advess,iNET6Advess,URL)可能涉及网络传输! 例如,DNS解析(url.equals,inetaddress from string!)。此呼叫可能需要很长时间,正在阻塞!

    对于ipv6,我有类似的东西。当然,这并不能处理非常细微的IPv6细节,比如只允许在某些类别的IPv6地址上使用区域索引。这个regex不是为组捕获而编写的,它只是一种“匹配”的regexp。

    S -IPv6段= [0-9a-f]{1,4}

    I - IPv4= (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})

    示意图(第一部分使用IPv4后缀匹配IPv6地址,第二部分使用IPv6地址,最后一部分使用区域索引):

    (
    (
    ::(S:){0,5}|
    S::(S:){0,4}|
    (S:){2}:(S:){0,3}|
    (S:){3}:(S:){0,2}|
    (S:){4}:(S:)?|
    (S:){5}:|
    (S:){6}
    )
    I
    
    |
    
    :(:|(:S){1,7})|
    S:(:|(:S){1,6})|
    (S:){2}(:|(:S){1,5})|
    (S:){3}(:|(:S){1,4})|
    (S:){4}(:|(:S){1,3})|
    (S:){5}(:|(:S){1,2})|
    (S:){6}(:|(:S))|
    (S:){7}:|
    (S:){7}S
    )
    
    (?:%[0-9a-z]+)?
    

    这里可能是regex(不区分大小写,围绕着任何需要的内容,如行首/行尾等):

    (?:
    (?:
    ::(?:[0-9a-f]{1,4}:){0,5}|
    [0-9a-f]{1,4}::(?:[0-9a-f]{1,4}:){0,4}|
    (?:[0-9a-f]{1,4}:){2}:(?:[0-9a-f]{1,4}:){0,3}|
    (?:[0-9a-f]{1,4}:){3}:(?:[0-9a-f]{1,4}:){0,2}|
    (?:[0-9a-f]{1,4}:){4}:(?:[0-9a-f]{1,4}:)?|
    (?:[0-9a-f]{1,4}:){5}:|
    (?:[0-9a-f]{1,4}:){6}
    )
    (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}
    (?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})|
    
    :(?::|(?::[0-9a-f]{1,4}){1,7})|
    [0-9a-f]{1,4}:(?::|(?::[0-9a-f]{1,4}){1,6})|
    (?:[0-9a-f]{1,4}:){2}(?::|(?::[0-9a-f]{1,4}){1,5})|
    (?:[0-9a-f]{1,4}:){3}(?::|(?::[0-9a-f]{1,4}){1,4})|
    (?:[0-9a-f]{1,4}:){4}(?::|(?::[0-9a-f]{1,4}){1,3})|
    (?:[0-9a-f]{1,4}:){5}(?::|(?::[0-9a-f]{1,4}){1,2})|
    (?:[0-9a-f]{1,4}:){6}(?::|(?::[0-9a-f]{1,4}))|
    (?:[0-9a-f]{1,4}:){7}:|
    (?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}
    )
    
    (?:%[0-9a-z]+)?
    
        10
  •  3
  •   Brad Gilbert    11 年前

    如果使用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);
    

    Validate::IP

    use Validate::IP qw'is_ipv6';
    
    if( is_ipv6($ip_address) ){
      print "Looks like an ipv6 address\n";
    }
    
        11
  •  3
  •   Rohit Malgaonkar    8 年前

    这将捕获环回(::1)以及IPv6地址。 将改为+并将:放在第一个方括号内。

    ([A-f0-9:]+:+)+[A-f0-9]+
    

    用ifconfig-a输出测试 http://regexr.com/

    Unix或Mac OSX终端O选项仅返回匹配的输出(IPv6),包括::1

    ifconfig -a | egrep -o '([A-f0-9:]+:+)+[A-f0-9]+'
    

    获取所有IP地址(IPv4或IPv6)并在Unix OSX终端上打印匹配

    ifconfig -a | egrep -o '([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) | (([A-f0-9:]+:+)+[A-f0-9]+)'
    
        12
  •  2
  •   David M. Syzdek    11 年前

    一个简单的regex将匹配,但我不建议任何类型的验证是:

    ([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}
    

    注意,这与地址中任何位置的压缩都匹配,尽管它与环回地址::1不匹配。我觉得这是一个合理的妥协,以保持regex简单。

    我在ITerm2中成功地使用了这个 智能选择规则 要四选一,请单击IPv6地址。

        13
  •  2
  •   the Tin Man    8 年前

    斯卡拉 使用著名的ApacheCommons验证器。

    http://mvnrepository.com/artifact/commons-validator/commons-validator/1.4.1

    libraryDependencies += "commons-validator" % "commons-validator" % "1.4.1"
    
    
    import org.apache.commons.validator.routines._
    
    /**
     * Validates if the passed ip is a valid IPv4 or IPv6 address.
     *
     * @param ip The IP address to validate.
     * @return True if the passed IP address is valid, false otherwise.
     */  
     def ip(ip: String) = InetAddressValidator.getInstance().isValid(ip)
    

    遵循方法的测试 ip(ip: String) :

    "The `ip` validator" should {
      "return false if the IPv4 is invalid" in {
        ip("123") must beFalse
        ip("255.255.255.256") must beFalse
        ip("127.1") must beFalse
        ip("30.168.1.255.1") must beFalse
        ip("-1.2.3.4") must beFalse
      }
    
      "return true if the IPv4 is valid" in {
        ip("255.255.255.255") must beTrue
        ip("127.0.0.1") must beTrue
        ip("0.0.0.0") must beTrue
      }
    
      //IPv6
      //@see: http://www.ronnutter.com/ipv6-cheatsheet-on-identifying-valid-ipv6-addresses/
      "return false if the IPv6 is invalid" in {
        ip("1200::AB00:1234::2552:7777:1313") must beFalse
      }
    
      "return true if the IPv6 is valid" in {
        ip("1200:0000:AB00:1234:0000:2552:7777:1313") must beTrue
        ip("21DA:D3:0:2F3B:2AA:FF:FE28:9C5A") must beTrue
      }
    }
    
        14
  •  1
  •   Community rcollyer    7 年前

    很难找到适用于所有IPv6情况的正则表达式。它们通常很难维护,不容易读取,并且可能导致性能问题。因此,我想分享一个我开发的替代解决方案: Regular Expression (RegEx) for IPv6 Separate from IPv4

    现在您可能会问,“此方法仅查找IPv6,如何在文本或文件中查找IPv6?”这里也有解决这个问题的方法。

    注释 :如果不想在.NET中使用IPAddress类,也可以将其替换为 my method . 它还包括映射的IPv4和特殊情况,而IP地址不包括。

    class IPv6
    {
        public List<string> FindIPv6InFile(string filePath)
        {
            Char ch;
            StringBuilder sbIPv6 = new StringBuilder();
            List<string> listIPv6 = new List<string>();
            StreamReader reader = new StreamReader(filePath);
            do
            {
                bool hasColon = false;
                int length = 0;
    
                do
                {
                    ch = (char)reader.Read();
    
                    if (IsEscapeChar(ch))
                        break;
    
                    //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                    if (!hasColon && length < 5)
                    {
                        if (ch == ':')
                        {
                            hasColon = true;
                        }
                        sbIPv6.Append(ch.ToString());
                    }
                    else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                    {
                        sbIPv6.Append(ch.ToString());
                    }
    
                    length++;
    
                } while (!reader.EndOfStream);
    
                if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
                {
                    listIPv6.Add(sbIPv6.ToString());
                }
    
                sbIPv6.Clear();
    
            } while (!reader.EndOfStream);
            reader.Close();
            reader.Dispose();
    
            return listIPv6;
        }
    
        public List<string> FindIPv6InText(string text)
        {
            StringBuilder sbIPv6 = new StringBuilder();
            List<string> listIPv6 = new List<string>();
    
            for (int i = 0; i < text.Length; i++)
            {
                bool hasColon = false;
                int length = 0;
    
                do
                {
                    if (IsEscapeChar(text[length + i]))
                        break;
    
                    //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                    if (!hasColon && length < 5)
                    {
                        if (text[length + i] == ':')
                        {
                            hasColon = true;
                        }
                        sbIPv6.Append(text[length + i].ToString());
                    }
                    else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                    {
                        sbIPv6.Append(text[length + i].ToString());
                    }
    
                    length++;
    
                } while (i + length != text.Length);
    
                if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
                {
                    listIPv6.Add(sbIPv6.ToString());
                }
    
                i += length;
                sbIPv6.Clear();
            }
    
            return listIPv6;
        }
    
        bool IsEscapeChar(char ch)
        {
            if (ch != ' ' && ch != '\r' && ch != '\n' && ch!='\t')
            {
                return false;
            }
    
            return true;
        }
    
        bool IsIPv6(string maybeIPv6)
        {
            IPAddress ip;
            if (IPAddress.TryParse(maybeIPv6, out ip))
            {
                return ip.AddressFamily == AddressFamily.InterNetworkV6;
            }
            else
            {
                return false;
            }
        }
    
    }
    
        15
  •  1
  •   the Tin Man    8 年前

    看看其他答案中包含的模式,有许多好的模式可以通过引用组和使用lookaheads来改进。下面是一个自引用模式的示例,如果必须这样做,我将在PHP中使用它:

    ^(?<hgroup>(?<hex>[[:xdigit:]]{0,4}) # grab a sequence of up to 4 hex digits
                                         # and name this pattern for usage later
         (?<!:::):{1,2})                 # match 1 or 2 ':' characters
                                         # as long as we can't match 3
     (?&hgroup){1,6} # match our hex group 1 to 6 more times
     (?:(?:
        # match an ipv4 address or
        (?<dgroup>2[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(?&dgroup)
        # match our hex group one last time
        |(?&hex))$
    

    注: PHP有一个内置的过滤器,这将是一个比这个更好的解决方案 模式。

    Regex101 Analysis

        16
  •  1
  •   the Tin Man    8 年前

    使用红宝石?试试这个:

    /^(((?=.*(::))(?!.*\3.+\3))\3?|[\dA-F]{1,4}:)([\dA-F]{1,4}(\3|:\b)|\2){5}(([\dA-F]{1,4}(\3|:\b|$)|\2){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/i
    
        17
  •  1
  •   Bill Lipa    8 年前

    根据您的需要,近似值如下:

    [0-9a-f:]+
    

    可能足够了(例如,使用简单的日志文件grepping)。

        18
  •  1
  •   Jitendra Gosavi    6 年前

    以下regex仅适用于IPv6。组1与IP匹配。

    (([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4})
    
        19
  •  0
  •   the Tin Man    12 年前

    在爪哇,可以使用图书馆类。 sun.net.util.IPAddressUtil :

    IPAddressUtil.isIPv6LiteralAddress(iPaddress);
    
        20
  •  0
  •   Wireblue    11 年前

    对于php 5.2+用户 filter_var 工作很好。

    我知道这并不能回答最初的问题(特别是一个regex解决方案),但是我把它贴出来,希望将来它能帮助其他人。

    $is_ip4address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== FALSE);
    $is_ip6address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== FALSE);
    
        21
  •  0
  •   the Tin Man    8 年前

    这将适用于IPv4和IPv6:

    ^(([0-9a-f]{0,4}:){1,7}[0-9a-f]{1,4}|([0-9]{1,3}\.){3}[0-9]{1,3})$
    
        22
  •  0
  •   the Tin Man    8 年前

    InetAddressUtils 定义了所有模式。我最终直接使用了他们的模式,并将其粘贴在这里以供参考:

    private static final String IPV4_BASIC_PATTERN_STRING =
            "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + // initial 3 fields, 0-255 followed by .
             "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; // final field, 0-255
    
    private static final Pattern IPV4_PATTERN =
        Pattern.compile("^" + IPV4_BASIC_PATTERN_STRING + "$");
    
    private static final Pattern IPV4_MAPPED_IPV6_PATTERN = // TODO does not allow for redundant leading zeros
            Pattern.compile("^::[fF]{4}:" + IPV4_BASIC_PATTERN_STRING + "$");
    
    private static final Pattern IPV6_STD_PATTERN =
        Pattern.compile(
                "^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$");
    
    private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
        Pattern.compile(
                "^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" + // 0-6 hex fields
                 "::" +
                 "(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); // 0-6 hex fields 
    
        23
  •  0
  •   the Tin Man    8 年前

    这就是我的想法,使用了一些前瞻性和命名组。这当然只是ipv6,但是如果您想添加ipv4,它不应该干扰其他模式:

    (?=([0-9a-f]+(:[0-9a-f])*)?(?P<wild>::)(?!([0-9a-f]+:)*:))(::)?([0-9a-f]{1,4}:{1,2}){0,6}(?(wild)[0-9a-f]{0,4}|[0-9a-f]{1,4}:[0-9a-f]{1,4})
    
        24
  •  0
  •   the Tin Man    8 年前

    你可以使用 the ipextract shell tools 我是为这个目的而做的。它们基于regexp和grep。

    用途:

    $ ifconfig | ipextract6
    fe80::1%lo0
    ::1
    fe80::7ed1:c3ff:feec:dee1%en0
    
        25
  •  0
  •   Mike Wilmes    8 年前

    我使用python生成了以下内容,并与re模块一起工作。前瞻性断言确保地址中出现正确数量的点或冒号。它不支持IPv6表示法中的IPv4。

    pattern = '^(?=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$)(?:(?:25[0-5]|[12][0-4][0-9]|1[5-9][0-9]|[1-9]?[0-9])\.?){4}$|(?=^(?:[0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}$)(?![^:]*::.+::[^:]*$)(?:(?=.*::.*)|(?=\w+:\w+:\w+:\w+:\w+:\w+:\w+:\w+))(?:(?:^|:)(?:[0-9a-f]{4}|[1-9a-f][0-9a-f]{0,3})){0,8}(?:::(?:[0-9a-f]{1,4}(?:$|:)){0,6})?$'
    result = re.match(pattern, ip)
    if result: result.group(0)
    
        26
  •  0
  •   Master James    7 年前

    只需将源代码中的本地代码与方括号进行匹配即可。我知道它没有那么全面,但是在javascript中,其他的很难跟踪问题,主要是那些不工作的问题,所以这似乎让我得到了我现在需要的东西。也不需要额外的大写字母a-f。

    ^\[([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})\]
    

    金科的版本简化了,我看得更好。

        27
  •  0
  •   Alexandre Fenyo    7 年前

    如上所述,获取ipv6文本表示的另一种方法 验证 解析器将使用编程。这里有一个完全符合RFC-4291和RFC-5952。我用ANSIC编写了这段代码(与GCC一起工作,在Linux上通过了测试-与Clang一起工作,在FreeBSD上通过了测试)。因此,它只依赖于ANSIC标准库,因此可以在任何地方编译(我已经使用它在具有freebsd的内核模块中进行了IPv6解析)。

    // IPv6 textual representation validating parser fully compliant with RFC-4291 and RFC-5952
    // BSD-licensed / Copyright 2015-2017 Alexandre Fenyo
    
    #include <string.h>
    #include <netinet/in.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <ctype.h>
    
    typedef enum { false, true } bool;
    
    static const char hexdigits[] = "0123456789abcdef";
    static int digit2int(const char digit) {
      return strchr(hexdigits, digit) - hexdigits;
    }
    
    // This IPv6 address parser handles any valid textual representation according to RFC-4291 and RFC-5952.
    // Other representations will return -1.
    //
    // note that str input parameter has been modified when the function call returns
    //
    // parse_ipv6(char *str, struct in6_addr *retaddr)
    // parse textual representation of IPv6 addresses
    // str:     input arg
    // retaddr: output arg
    int parse_ipv6(char *str, struct in6_addr *retaddr) {
      bool compressed_field_found = false;
      unsigned char *_retaddr = (unsigned char *) retaddr;
      char *_str = str;
      char *delim;
    
      bzero((void *) retaddr, sizeof(struct in6_addr));
      if (!strlen(str) || strchr(str, ':') == NULL || (str[0] == ':' && str[1] != ':') ||
          (strlen(str) >= 2 && str[strlen(str) - 1] == ':' && str[strlen(str) - 2] != ':')) return -1;
    
      // convert transitional to standard textual representation
      if (strchr(str, '.')) {
        int ipv4bytes[4];
        char *curp = strrchr(str, ':');
        if (curp == NULL) return -1;
        char *_curp = ++curp;
        int i;
        for (i = 0; i < 4; i++) {
          char *nextsep = strchr(_curp, '.');
          if (_curp[0] == '0' || (i < 3 && nextsep == NULL) || (i == 3 && nextsep != NULL)) return -1;
          if (nextsep != NULL) *nextsep = 0;
          int j;
          for (j = 0; j < strlen(_curp); j++) if (_curp[j] < '0' || _curp[j] > '9') return -1;
          if (strlen(_curp) > 3) return -1;
          const long val = strtol(_curp, NULL, 10);
          if (val < 0 || val > 255) return -1;
          ipv4bytes[i] = val;
          _curp = nextsep + 1;
        }
        sprintf(curp, "%x%02x:%x%02x", ipv4bytes[0], ipv4bytes[1], ipv4bytes[2], ipv4bytes[3]);
      }
    
      // parse standard textual representation
      do {
        if ((delim = strchr(_str, ':')) == _str || (delim == NULL && !strlen(_str))) {
          if (delim == str) _str++;
          else if (delim == NULL) return 0;
          else {
            if (compressed_field_found == true) return -1;
            if (delim == str + strlen(str) - 1 && _retaddr != (unsigned char *) (retaddr + 1)) return 0;
            compressed_field_found = true;
            _str++;
            int cnt = 0;
            char *__str;
            for (__str = _str; *__str; ) if (*(__str++) == ':') cnt++;
            unsigned char *__retaddr = - 2 * ++cnt + (unsigned char *) (retaddr + 1);
            if (__retaddr <= _retaddr) return -1;
            _retaddr = __retaddr;
          }
        } else {
          char hexnum[4] = "0000";
          if (delim == NULL) delim = str + strlen(str);
          if (delim - _str > 4) return -1;
          int i;
          for (i = 0; i < delim - _str; i++)
            if (!isxdigit(_str[i])) return -1;
            else hexnum[4 - (delim - _str) + i] = tolower(_str[i]);
          _str = delim + 1;
          *(_retaddr++) = (digit2int(hexnum[0]) << 4) + digit2int(hexnum[1]);
          *(_retaddr++) = (digit2int(hexnum[2]) << 4) + digit2int(hexnum[3]);
        }
      } while (_str < str + strlen(str));
      return 0;
    }
    
        28
  •  0
  •   Sean F    7 年前

    当您考虑具有嵌入式IPv4的地址和压缩的地址时,IPv6的regex可能会变得非常棘手,从这些答案中可以看到。

    The open-source IPAddress Java library 将验证ipv6和ipv4的所有标准表示,并支持前缀长度(以及验证前缀长度)。免责声明:我是那个图书馆的项目经理。

    代码示例:

            try {
                IPAddressString str = new IPAddressString("::1");
                IPAddress addr = str.toAddress();
                if(addr.isIPv6() || addr.isIPv6Convertible()) {
                    IPv6Address ipv6Addr = addr.toIPv6();
                }
                //use address
            } catch(AddressStringException e) {
                //e.getMessage has validation error
            }
    
        29
  •  -1
  •   Carlos Velazquez    8 年前

    试试这个小的一衬。它应该只匹配有效的未压缩/压缩的IPv6地址(没有IPv4混合)

    /(?!.*::.*::)(?!.*:::.*)(?!:[a-f0-9])((([a-f0-9]{1,4})?[:](?!:)){7}|(?=(.*:[:a-f0-9]{1,4}::|^([:a-f0-9]{1,4})?::))(([a-f0-9]{1,4})?[:]{1,2}){1,6})[a-f0-9]{1,4}/
    
        30
  •  -2
  •   Jason Plank dvancouver    13 年前

    regex允许在IPv4部分使用前导零。

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

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