Expression régulière (RegEx) pour IPv6 séparée de IPv4

s'il vous plaît lire avant de marquer en tant que duplicata

Je n'ai pas été en mesure de créer ou trouver un RegEx qui fonctionne pour tous formats IPv6 (mes cas de test sont ci-dessous). Je suis conscient de cette question que tout le monde pointe à: Expression régulière qui correspond adresses IPv6 valides cependant, ils combinent tous IPv6 avec IPv4 et/ou ne fonctionnent pas avec tous mes cas de test.

Prescriptions:

  1. Je ne veux pas qu'il valide également les valeurs IPv4, j'ai déjà une fonction de validation séparée pour IPv4.
  2. j'ai besoin d'un modèle qui fonctionne en Coldfusion et un modèle qui fonctionne en PL/SQL .
  3. parce que je l'utilise dans PL/SQL le motif doit rester sous 512 caractères . Oracle ne supporte qu'une partie étroite du langage RegExp. De sorte que le Le modèle ColdFusion pourrait finir par être différent du modèle PL/SQL , ce qui est bien, tant qu'ils fonctionnent tous les deux.
  4. résultat final n'a pas un long RegEx, il peut être divisé.

voici le dernier modèle que j'essaie:

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

cela se rapproche pour ColdFusion mais pas à 100%. Ça ne marche pas du tout dans PL/SQL .

Résultats Des Essais http://regex101.com/r/wI8cI0 Le bold les articles sont celles que le modèle ne fonctionne pas en ColdFusion :

  1. match
  2. match
  3. match
  4. match
  5. match
  6. match (mais @Michael Hampton dit que cela ne devrait pas correspondre parce que ce N'est pas un IPv6 valide adresse, mais d'autres m'ont dit qu'il est valide, donc je ne suis pas sûr de ce cas de test.)
  7. match ( :: est en fait un format valide, Merci @Sander Steffann.)
  8. match
  9. aucun match
  10. match
  11. aucun match
  12. aucun match
  13. aucun match
  14. match
  15. match
  16. aucun match
  17. aucun match
  18. aucun match
  19. aucun match

j'ai des cas d'essai 8-11 de: http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzai2%2Frzai2ipv6addrformat.htm Et a été dit: Test 9 et 11 sont pour le préfixe D'adresse IPv6, pas une adresse IPv6, donc ceux-ci ne devraient pas être assortis.

résultat final, j'ai besoin qu'ils travaillent dans des déclarations comme celle-ci:

ColdFusion:

<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
1
demandé sur Community 2014-02-07 19:31:08

3 réponses

en ce qui concerne la recherche, il n'y a pas de RegEx qui fonctionne pour tous les formats IPv6. Même il l'est, c'est tellement complexe et difficile à maintenir (pas très lisible). En outre, il peut causer des problèmes de performances. Donc j'ai décidé d'écrire une méthode (fonction) pour cela. Vous pouvez facilement ajouter tout cas particuliers comme vous le souhaitez. Je l'ai écrit en C#, mais je pense que vous pouvez convertir cet algorithme en n'importe quelle langue:

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;
    }

}

j'ai aussi ajouté d'autres méthodes comme comment rechercher IPv6 en texte ou en Fichier aussi. Vous pouvez vérifier: L'expression régulière qui correspond aux adresses IPv6 valides

Résumé de modification : Ipv4 mappées et des caractères spéciaux ont été visés comme "::123.23.23.23", "fe80::3%eth0", "::ffff:192.1.56.10/96".

2
répondu Nuh Metin Güler 2017-05-23 10:32:33

:: est une adresse IPv6 valide (zéros adresse), alors pourquoi ne pas l'accepter?

et si vous ne voulez pas accepter les adresses IPv6 avec les derniers 32 bits écrits en notation IPv4 (pourquoi ne le feriez-vous pas, ils sont des représentations d'adresse valides) alors il suffit de révoquer la dernière partie de la regex qui traite avec eux (à partir de ::(ffff ).

quoi qu'il en soit, la regex contient effectivement quelques erreurs dans la partie de notation IPv4. L'IPv4 la notation est juste une façon différente d'écrire les 32 derniers bits de l'adresse IPv6, et la regex ne gère pas toutes les variantes. En outre, il oublie même d'échapper à la . de sorte qu'il acceptera également de nombreuses chaînes invalides.

1
répondu Sander Steffann 2014-02-07 16:23:19

avec beaucoup d'aide de @nhahtdh dans cette réponse https://stackoverflow.com/a/21943960/3112803 j'ai trouvé le fait de le briser pour être la meilleure solution. Ci-dessous est un exemple de comment le faire dans PL/SQL , mais il pourrait être fait de cette façon dans d'autres langues. Je ferai la même chose dans ColdFusion . Pour PL/SQL le motif nécessaire pour rester en dessous de 512 caractères donc la briser fonctionne bien et il est simple à comprendre. Il a passé tout mon exemples dans la question originale.

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
0
répondu gfrobenius 2017-05-23 12:10:53