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

Posted

技术标签:

【中文标题】匹配所有有效格式 IPv6 地址的正则表达式【英文标题】:Regular expression that matches all valid format IPv6 addresses 【发布时间】:2015-11-28 20:07:29 【问题描述】:

乍一看,我承认这个问题看起来像是这个问题的副本以及与之相关的任何其他问题:

Regular expression that matches valid IPv6 addresses

事实上,这个问题的答案几乎可以回答我的问题,但不完全。

我遇到问题但最成功的那个问题的代码如下所示:

private string RemoveIPv6(string sInput)

    string pattern = @"(([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(:01,4)0,1:)0,1((25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])\.)3,3(25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])|([0-9a-fA-F]1,4:)1,4:((25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])\.)3,3(25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9]))";
    //That is one looooong regex! From: https://***.com/a/17871737/3472690
    //if (IsCompressedIPv6(sInput))
      //  sInput = UncompressIPv6(sInput);
    string output = Regex.Replace(sInput, pattern, "");
    if (output.Contains("Addresses"))
        output = output.Substring(0, "Addresses: ".Length);

    return output;

我在这个答案David M. Syzdek's Answer 中提供的正则表达式模式存在的问题是它不匹配并删除了我向它抛出的 IPv6 地址的完整形式。

我正在使用正则表达式模式主要用空格或空值替换字符串中的 IPv6 地址。

例如,

    Addresses:  2404:6800:4003:c02::8a

还有……

    Addresses:  2404:6800:4003:804::200e

最后……

    Addresses:  2001:4998:c:a06::2:4008

所有要么没有被正则表达式完全匹配,要么没有完全匹配。

正则表达式将返回字符串的其余部分,如下所示:

    Addresses:  8a

    Addresses:  200e

    Addresses:  2:4008

可以看出,它留下了 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(:01,4)0,1:)0,1((25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])\.)3,3(25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])|([0-9a-fA-F]1,4:)1,4:((25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])\.)3,3(25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9]))

因此,我的问题是,如何更正此正则表达式模式以使其匹配,从而允许从不单独包含 IPv6 的字符串中完全删除任何 IPv6 地址地址本身?

或者,我上面提供的代码 sn-p 如何更正以提供所需的结果?

对于那些可能想知道的人,我从 nslookup 命令的 StandardOutput 获取字符串,而 IPv6 地址总是不同的。对于上面的示例,我从“google.com”和“yahoo.com”获得了这些 IPv6 地址。

我没有使用内置函数来解析 DNS 条目是有充分理由的,我认为这暂时不重要,因此我正在使用 nslookup。

如果需要,调用该函数的代码如下:(它本身也是另一个函数/方法,或者说是其中的一部分)

string output = "";
string garbagecan = "";
string tempRead = "";
string lastRead = "";
using (StreamReader reader = nslookup.StandardOutput)

     while (reader.Peek() != -1)
     
         if (LinesRead > 3)
         
             tempRead = reader.ReadLine();
             tempRead = RemoveIPv6(tempRead);

             if (tempRead.Contains("Addresses"))
                 output += tempRead;
             else if (lastRead.Contains("Addresses"))
                 output += tempRead.Trim() + Environment.NewLine;
             else
                 output += tempRead + Environment.NewLine;
             lastRead = tempRead;
         
         else
             garbagecan = reader.ReadLine();
         LinesRead++;
     
 
 return output;

更正后的正则表达式应该只允许删除 IPv6 地址,而保持 IPv4 地址不变。 将传递给正则表达式的字符串不会单独包含 IPv6 地址,并且几乎总是包含其他详细信息,因此,无法预测地址将出现在哪个索引处。出于某种原因,正则表达式也会在第一个出现的 IPv6 地址之后跳过所有其他 IPv6 地址。

抱歉,如果有任何遗漏的细节,我会尽力在收到提醒时将它们包括在内。如果可能的话,我也更喜欢工作代码示例,因为我对正则表达式的了解几乎为零。

【问题讨论】:

@nhahtdh 我猜你没有读过这个问题。这是基于该答案,我已经在使用它,但发现它有很多缺陷(更多信息在问题中)。您实际上可以检查上面提供的正则表达式模式与该答案中的模式;他们是一样的。 vks 已经提供了一个比这更好的替代方案,但它没有我遇到的问题。 @nhahtdh 您还可以将regex101.com/r/zI1mQ6/1 上那个答案和这个问题的正则表达式与 vks 在regex101.com/r/cT0hV4/5 上提供的正则表达式进行比较。 啊,对不起。我以为vks的答案不包括链接本地格式%,但实际上是基于那个答案。评论已撤消。 【参考方案1】:
(?:^|(?<=\s))(([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(:01,4)0,1:)0,1((25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])\.)3,3(25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])|([0-9a-fA-F]1,4:)1,4:((25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9])\.)3,3(25[0-5]|(2[0-4]|10,1[0-9])0,1[0-9]))(?=\s|$)

使用lookarounds,您可以强制执行完全匹配而不是partial 匹配。参见演示。

https://regex101.com/r/cT0hV4/5

【讨论】:

谢谢,nslookup 为“yahoo.com”、“google.com”和“abc.xyz”返回的 IPv6 地址可以正常工作(我知道的仅有少数会返回 IPv6 和 IPv4 地址)。 :) 您能否在链接的问题中回答,以便可以将其作为重复关闭?或者也许要求合并? @AlexeiLevenkov 这实际上不是重复的。猜猜我们应该保持原样:) \A(?:[A-Fa-f0-9]1,4:)7[A-Fa-f0-9]1,4 有什么问题吗\Z 这是真正检测所有 IPv6 情况(包括压缩 IPv6)的解决方案

以上是关于匹配所有有效格式 IPv6 地址的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

IP地址(IPv4)/IPv6地址的正则表达式

正则---让人喜欢让人忧

我可以使用啥正则表达式来匹配以点十进制表示法表示的任何有效 IP 地址?

如何将大字符串中的子字符串与正则表达式匹配? [复制]

使用正则表达式匹配 yyyymmdd 中的日期格式

用于验证 IPv4 和 IPv6 地址的 Javascript 正则表达式,没有主机名