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

16

乍一看,我承认这个问题看起来像是这个问题和任何与它相关的问题的重复:

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

实际上,那个问题确实有一个几乎回答了我的问题的答案,但不完全。

我有问题的那个问题中的代码,却取得了最大的成功:

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(: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]))";
    //That is one looooong regex! From: https://dev59.com/qHVD5IYBdhLWcg3wNIvc#17871737
    //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的答案,它不能匹配和删除我输入的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(: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地址本身的字符串中完全删除任何IPv6地址?

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

对于那些可能会感到好奇的人,我正在从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已经提供了一个更好的替代方案,比那个更好,而且没有我遇到的任何问题。 - Kaitlyn
@nhahtdh,你还可以在 https://regex101.com/r/zI1mQ6/1 上比较这个问题的正则表达式和那个回答的正则表达式,以及 vks 提供的正则表达式在 https://regex101.com/r/cT0hV4/5 上。 - Kaitlyn
1
啊,对不起。我以为vks的回答没有包含本地链接格式,但实际上是基于那个答案的。评论已撤回。 - nhahtdh
2个回答

16
(?:^|(?<=\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(: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]))(?=\s|$)

使用 lookarounds 可以强制进行完整匹配而不是部分匹配。请参见演示。

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


谢谢,使用 nslookup 返回的 IPv6 地址,对于 "yahoo.com"、"google.com" 和 "abc.xyz"(我知道的仅有的几个同时返回 IPv6 和 IPv4 地址的网站)都能完美运行。 :) - Kaitlyn
你能否在链接的问题中回答,以便将其关闭为重复问题?或者可能要求合并吗? - Alexei Levenkov
1
@AlexeiLevenkov 这实际上不是重复的。我想我们应该将其保留为原样 :) - vks
@NikhilVerma \A 只匹配字符串的开头,即使它是多行的...但在这里,字符串将匹配任何行的开头或空格后。 - vks
1
这是真正检测所有IPv6情况的解决方案(包括压缩的IPv6)。 - innovatism
显示剩余2条评论

2
(?i)(?<ipv6>(?:[\da-f]{0,4}:){1,7}(?:(?<ipv4>(?:(?:25[0-5]|2[0-4]\d|1?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1?\d\d?))|[\da-f]{0,4}))

演示: Regex101

Github代码库


1
不错的解决方案,请更新您的答案以区分v6和v4:/(?i)(?<ipv6>(?:[\da-f]{0,4}:){1,7}(?:(?<ipv4>(?:(?:25[0-5]|2[0-4]\d|1?\d\d?).){3}(?:25[0-5]|2[0-4]\d|1?\d\d?))|[\da-f]{0,4}))/gm - Mecanik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接