独立于IPv4的IPv6正则表达式(RegEx)

fjnneemd  于 2022-11-26  发布在  其他
关注(0)|答案(4)|浏览(175)

请在标记为重复之前阅读

我还没有能够创建或找到一个适用于 * 所有 * IPv6格式的RegEx(我的测试案例如下)。我知道每个人都指向这个问题:Regular expression that matches valid IPv6 addresses但是,它们都将IPv6与IPv4结合在一起,并且/或者不适用于我的所有测试用例。
要求:
1.我不想让它也验证IPv4值,我已经有一个单独的IPv4验证函数。
1.我需要一个在Coldfusion中工作的模式和一个在PL/SQL中工作的模式。
1.因为我在PL/SQL中使用它,所以它的模式必须保持在512个字符以下。Oracle只支持RegExp语言的一小部分。所以ColdFusion模式最终可能与PL/SQL模式不同,这没关系,只要它们都能工作。
1.最终结果不一定是一个长的RegEx,它可以被拆分。
下面是我正在尝试的最新模式:

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

这对于ColdFusion来说很接近,但不是100%,在PL/SQL中根本不起作用。
测试结果**http://regex101.com/r/wI8cI0****bold项是模式在ColdFusion中不起作用的项:
1.相匹配
1.相匹配
1.相匹配
1.相匹配
1.相匹配
1.match(但是@Michael汉普顿说这不应该匹配,因为它不是有效的IPv6地址,但是其他人告诉我它是有效的,所以我不确定这个测试用例。)
1.匹配(::实际上是一个有效格式,谢谢@Sander Steffann。)
1.相匹配
1.无匹配项
1.相匹配
1.无匹配项
1.无匹配项
1.无匹配项
1.相匹配
1.相匹配
1.无匹配项
1.无匹配项
1.无匹配项
1.无匹配项
测试用例8-11来自:http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzai2%2Frzai2ipv6addrformat.htm有人告诉我:测试9和11针对的是IPv6地址前缀,而不是IPv6地址,因此它们不应匹配。
最终结果,我需要他们在这样的语句中工作:
您可以:

<cfset IndexOfOccurrence1=REFind("^(?>(?>([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
aiazj4mn

aiazj4mn1#

在@nhahtdh的帮助下,我发现把它分解是最好的解决方案。下面是一个在PL/SQL中如何做的例子,但在其他语言中也可以这样做。我将在ColdFusion中做同样的事情。对于PL/SQL,模式需要保持在512个字符以下,所以分解它效果很好,而且很容易理解。它通过了我在最初问题中的所有测试案例。

if (
    /* IPv6 expanded */
    REGEXP_LIKE(v, '\A[[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){7}\z')
    /* IPv6 shorthand */
    OR (NOT REGEXP_LIKE(v, '\A(.*?[[:xdigit:]](:|\z)){8}')
    AND REGEXP_LIKE(v, '\A([[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){0,6})?::([[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){0,6})?\z'))
    /* IPv6 dotted-quad notation, expanded */
    OR REGEXP_LIKE(v, '\A[[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){5}:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z')
    /* IPv6 dotted-quad notation, shorthand */
    OR (NOT REGEXP_LIKE(v, '\A(.*?[[:xdigit:]]:){6}')
    AND REGEXP_LIKE(v, '\A([[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){0,4})?::([[:xdigit:]]{1,4}:){0,5}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z'))
) then
5fjcxozz

5fjcxozz2#

据我所知,没有一个RegEx可以适用于所有的IPv6格式。即使有,它也是如此复杂,难以维护(不易读取)。此外,它还可能导致性能问题。因此,我决定为此编写一个方法(函数)。您也可以根据需要轻松添加任何特殊情况。我用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。您可以检查:与有效IPv6地址匹配的正则表达式

编辑摘要:已涵盖Ipv4Map字符和特殊字符,如“::123.23.23.23“、“fe80::3%eth0”、“::ffff:192.1.56.10/96“。

368yc8dk

368yc8dk3#

::是有效的IPv6地址(全零地址),为什么不接受它呢?
如果你不想接受最后32位用IPv4表示法写的IPv6地址(为什么不呢,它们是有效的地址表示法),那么只需撤销处理它们的正则表达式的最后一部分(从::(ffff开始)。
无论如何,正则表达式确实在IPv4表示法部分包含一些错误。IPv4表示法只是写入IPv6地址最后32位的一种不同方式,正则表达式并不处理所有有效的变体。此外,它甚至忘记转义.,因此它也将接受许多无效字符串。

mspsb9vt

mspsb9vt4#

这是一个综合性的IPv6正则表达式,用于测试所有有效的IPv6文本表示法(expanded、compressed、expanded-mixed、compressed-mixed)以及可选的前缀长度。它还将各个部分捕获到捕获组中。通过在捕获组的左括号后面放置?:,可以跳过捕获组。
这是我在IPvX IP calculator中为IPv4和IPv6创建并使用的正则表达式。

^# Anchor
  (# BEGIN Compressed-mixed                                         *** Group 1 ***
    (# BEGIN Hexadecimal Notation                                   *** Group 2 ***
       (?:
         (?:[0-9A-F]{1,4}:){5}[0-9A-F]{1,4}            # No ::
       | (?:[0-9A-F]{1,4}:){4}:[0-9A-F]{1,4}           # 4::1
       | (?:[0-9A-F]{1,4}:){3}(?::[0-9A-F]{1,4}){1,2}  # 3::2
       | (?:[0-9A-F]{1,4}:){2}(?::[0-9A-F]{1,4}){1,3}  # 2::3
       | [0-9A-F]{1,4}:(?::[0-9A-F]{1,4}){1,4}         # 1::4
       | (?:[0-9A-F]{1,4}:){1,5}                       # :: End
       | :(?::[0-9A-F]{1,4}){1,5}                      # :: Start
       | :                                             # :: Only
       ):
    )# END Hexadecimal Notation
    (# BEGIN Dotted-decimal Notation                                *** Group 3 ***
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\. # 0 to 255.  *** Group 4 ***
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\. # 0 to 255.  *** Group 5 ***
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\. # 0 to 255.  *** Group 6 ***
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])   # 0 to 255   *** Group 7 ***
    )# END Dotted-decimal Notation
  )# END Compressed-mixed
  |
  (# BEGIN Compressed                                               *** Group 8 ***
     (?:# BEGIN Hexadecimal Notation
       (?:[0-9A-F]{1,4}:){7}[0-9A-F]{1,4}              # No ::
     | (?:[0-9A-F]{1,4}:){6}:[0-9A-F]{1,4}             # 6::1
     | (?:[0-9A-F]{1,4}:){5}(?::[0-9A-F]{1,4}){1,2}    # 5::2
     | (?:[0-9A-F]{1,4}:){4}(?::[0-9A-F]{1,4}){1,3}    # 4::3
     | (?:[0-9A-F]{1,4}:){3}(?::[0-9A-F]{1,4}){1,4}    # 3::4
     | (?:[0-9A-F]{1,4}:){2}(?::[0-9A-F]{1,4}){1,5}    # 2::5
     | [0-9A-F]{1,4}:(?::[0-9A-F]{1,4}){1,6}           # 1::6
     | (?:[0-9A-F]{1,4}:){1,7}:                        # :: End
     | :(?::[0-9A-F]{1,4}){1,7}                        # :: Start
     | ::                                              # :: Only
     )  # END Hexadecimal Notation
  )# END Compressed
  (?:# BEGIN Optional Length
       /(12[0-8]|1[0-1][0-9]|[1-9]?[0-9])              # /0 to /128 *** Group 9 ***
  )? # END Optional Length
$# Anchor

附加IPv4正则表达式:

^# Anchor
  (?:# BEGIN Dotted-decimal Notation
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\. # 0 to 255.  *** Group 1 ***
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\. # 0 to 255.  *** Group 2 ***
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\. # 0 to 255.  *** Group 3 ***
       (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])   # 0 to 255   *** Group 4 ***
  )  # END Dotted-decimal Notation
  (?:# BEGIN Optional Length
       /(3[0-2]|[1-2]?[0-9])                           # /0 to /32  *** Group 5 ***
  )? # END Optional Length
$# Anchor

相关问题