IPv6与IPv4分开的正则表达式(RegEx)

17 浏览
0 Comments

IPv6与IPv4分开的正则表达式(RegEx)

请在标记为重复之前阅读

我无法创建或找到适用于所有IPv6格式的正则表达式(我的测试用例如下)。我知道大家都指向这个问题:匹配有效IPv6地址的正则表达式。然而,它们都将IPv6与IPv4结合起来,或者不能适用于我所有的测试用例。

要求:

  1. 我不希望它也验证IPv4值,我已经有一个单独的验证函数用于IPv4。
  2. 我需要一个适用于冷冻融合的模式和一个适用于PL / SQL的模式。
  3. 因为我在PL / SQL中使用它,所以它的模式必须保持小于512个字符。而且Oracle只支持RegExp语言的一小部分。所以冷融模式可能与PL / SQL模式不同,这没关系,只要它们都有效。
  4. 最终结果不一定是一个长的正则表达式,可以分开。

这是我正在尝试的最新模式:

^(?>(?>([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}))$

这在冷融中接近,但不完全适用。在PL / SQL中根本不起作用。

测试结果https://regex101.com/r/wI8cI0 粗体项是模式在冷融中不适用的项:

  1. 匹配
  2. 匹配
  3. 匹配
  4. 匹配
  5. 匹配
  6. 匹配(但Michael Hampton说这不应该匹配,因为它不是一个有效的IPv6地址,但其他人告诉我它是有效的,所以我对这个测试案例不确定。)
  7. 匹配(::实际上是一个有效的格式,谢谢Sander Steffann。)
  8. 匹配
  9. 不匹配
  10. 匹配
  11. 不匹配
  12. 不匹配
  13. 不匹配
  14. 匹配
  15. 匹配
  16. 不匹配
  17. 不匹配
  18. 不匹配
  19. 不匹配

我从这里获取了测试案例8-11:https://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzai2%2Frzai2ipv6addrformat.htm

并被告知:测试案例9和11是IPv6地址前缀,而不是IPv6地址,所以不应该匹配。

最终结果,我需要它们在如下语句中起作用:

冷融:

(?>([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}))$",value[i])>

PL / SQL:

if ( REGEXP_LIKE(v,'^(?>(?>([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}))$','i') ) then

0
0 Comments

问题的出现原因:正则表达式(RegEx)用于匹配IPv6地址和IPv4地址,但存在一些问题。首先,正则表达式没有正确处理IPv4表示法的所有有效变体,甚至忘记转义点号,导致它接受了许多无效的字符串。其次,正则表达式没有处理IPv6地址中最后32位使用IPv4表示法的情况。

解决方法:如果不想接受最后32位使用IPv4表示法的IPv6地址,只需删除处理这种情况的正则表达式部分(从::(ffff开始)。如果想接受最后32位使用IPv4表示法的IPv6地址,需要修改正则表达式的最后部分,使其接受每个可能位置的双冒号(正则表达式的第一部分)以及IPv4表示法。建议使用现有的地址解析程序来处理IPv6地址,而不是尝试将所有内容放入一个复杂的(因此容易出错的)正则表达式中。

以下是一个示例的正则表达式,用于匹配IPv4地址:(((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?))。如果想将其添加到解决IPv4问题的正则表达式中,需要修改最后部分,使其接受双冒号的每个可能位置以及IPv4表示法。

原文链接:regex101.com/r/mO4hJ2

如果只想要匹配纯IPv6地址而不与IPv4地址组合,建议不要使用复杂的正则表达式,而是使用现有的地址解析程序。

0
0 Comments

文章标题:IPv6与IPv4分开的正则表达式(RegEx)的出现原因及解决方法

在我进行研究的过程中,我发现没有一个适用于所有IPv6格式的正则表达式(RegEx)。即使有,它也非常复杂且难以维护(不容易阅读)。此外,它还可能导致性能问题。因此,我决定编写一个方法(函数)来解决这个问题。您还可以根据需要添加任何特殊情况。我用C#编写了这个算法,但我认为您可以将这个算法转换为任何编程语言:

class IPv6Validator
{
    string charValidator = @"[A-Fa-f0-9]";
    string IPv4Validation = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
    public bool IsIPv6(string maybeIPv6)
    {
        if (maybeIPv6 == "::")
        {
            return true;
        }
        int numberOfEmptyDigitGroups = 0;
        int expectedDigitGroupsLength = 8;
        string[] arrMaybeIPv6 = maybeIPv6.Split(':');
        if (arrMaybeIPv6.Length > 9 || arrMaybeIPv6.Length < 3)
        {
            return false;
        }
        for (int i = 0; i < arrMaybeIPv6.Length; i++)
        {
            //IF IPv6 starts or ends with "::" (ex ::1)
            if ((i == 0 || i == arrMaybeIPv6.Length - 2) && IsEmptyDigitGroup(arrMaybeIPv6[i]) && IsEmptyDigitGroup(arrMaybeIPv6[i+1]))
            {
                expectedDigitGroupsLength = 9;
                numberOfEmptyDigitGroups++;
                i++;
            }
            else if (arrMaybeIPv6[i].Trim() == string.Empty) //If IPv6 contains :: (ex 1:2::3)
            {
                numberOfEmptyDigitGroups++;
            }
            //Cannot have more than one "::"  (ex ::1:2::3)
            if (numberOfEmptyDigitGroups > 1)
            {
                return false;
            }
            //Mapped IPv4 control
            if (i == arrMaybeIPv6.Length - 1 && IsIPv4(arrMaybeIPv6[i]) && arrMaybeIPv6.Length < 8)
            {
                return true;
            }
            else if (i == arrMaybeIPv6.Length - 1 && HasSpecialCharInIPv6(arrMaybeIPv6[i], IsEmptyDigitGroup(arrMaybeIPv6[i - 1]))) //If last digit group contains special char (ex fe80::3%eth0)
            {
                return true;
            }
            else //if not IPV4, check the digits
            {
                //Cannot have more than 4 digits (ex 12345:1::)
                if (arrMaybeIPv6[i].Length > 4)
                {
                    return false;
                }
                //Check if it has unvalid char
                foreach (char ch in arrMaybeIPv6[i])
                {
                    if (!IsIPv6Char(ch.ToString()))
                    {
                        return false;
                    }
                }
            }
            //Checks if it has extra digit (ex 1:2:3:4:5:6:7:8f:)
            if (i >= expectedDigitGroupsLength)
            {
                return false;
            }
            //If it has missing digit at last or end (ex 1:2:3:4:5:6:7:)
            if ((i == 0 || i == arrMaybeIPv6.Length - 1) && IsEmptyDigitGroup(arrMaybeIPv6[i]) && expectedDigitGroupsLength != 9)
            {
                return false;
            }
            //If it has missing digits (ex 1:2:3:4:5:6)
            if (i == arrMaybeIPv6.Length - 1 && numberOfEmptyDigitGroups == 0 && arrMaybeIPv6.Length < 8)
            {
                return false;
            }
        }
        return true;
    }
    bool IsIPv4(string lastDigitGroup)
    {
        //If lastDigitGroup has special char, then get the first group for IPV4 validation (ex ::123.12.2.1/60)
        string maybeIPv4 = lastDigitGroup.Split('/','%')[0];
        Match match = Regex.Match(maybeIPv4, IPv4Validation);
        return match.Success;
    }
    bool IsIPv6Char(string strChar)
    {
        Match match = Regex.Match(strChar, charValidator);
        return match.Success;
    }
    bool IsSpecialChar(char ch)
    {
        if (ch == '%' || ch == '/')
        {
            return true;
        }
        return false;
    }
    bool HasSpecialCharInIPv6(string lastDigitGroup, bool isPreviousDigitGroupEmpty)
    {
        for (int i = 0; i < lastDigitGroup.Length; i++)
        {
            //If cannot find any special char at first 5 chars then leave the for loop
            if (i == 5)
                break;
            //If the first digit is special char, check the previous digits to be sure it is a valid IPv6 (ex FE80::/10)
            if (i == 0 && IsSpecialChar(lastDigitGroup[i]) && isPreviousDigitGroupEmpty)
                return true;
            if (i != 0 && IsSpecialChar(lastDigitGroup[i]))
                return true;
            if (!IsIPv6Char(lastDigitGroup[i].ToString()))
                return false;
        }
        return false;
    }
    bool IsEmptyDigitGroup(string digitGroup)
    {
        if (digitGroup.Trim() == string.Empty)
            return true;
        return false;
    }
}

我还添加了其他方法,如如何在文本或文件中搜索IPv6。您可以参考:Regular expression that matches valid IPv6 addresses

编辑摘要:已经涵盖了IPv4映射和特殊字符,例如"::123.23.23.23","fe80::3%eth0","::ffff:192.1.56.10/96"。

"在我进行研究的过程中,我发现没有一个适用于所有IPv6格式的正则表达式(RegEx)。" 您可以在这里查看我的答案,其中包含一个可以匹配所有有效IPv6地址格式的IPv6正则表达式。

0
0 Comments

问题的出现原因是需要通过正则表达式将IPv6地址和IPv4地址分开。作者在这段代码中使用了PL/SQL编程语言示例,但也可以使用其他编程语言来实现相同的功能。

解决方法是使用正则表达式来匹配IPv6地址和IPv4地址的模式。作者在代码中使用了几个不同的正则表达式模式来匹配不同类型的IPv6和IPv4地址。

代码示例中的正则表达式模式包括:

- 匹配IPv6扩展格式的地址

- 匹配IPv6简写格式的地址

- 匹配IPv6点分十进制格式的地址(扩展)

- 匹配IPv6点分十进制格式的地址(简写)

通过使用这些正则表达式模式,作者能够将IPv6地址和IPv4地址分开,并根据需要采取相应的操作。

这段代码通过使用正则表达式模式来解决了将IPv6地址和IPv4地址分开的问题,同时还通过测试用例验证了代码的正确性。

0