Проверяйте группы регулярных выражений с помощью ИЛИ, когда обе группы присутствуют в коде Java.

Необходимо проверить формат, в котором могут присутствовать либо транспорт, либо протокол, либо оба. Я применил это регулярное выражение для проверки группы. Но когда какая-либо проверка проходит успешно, она не проверяет другую группу, как в коде. Примечание: транспорт может принимать либо tcp, sctp или udp, а протокол может принимать радиус, диаметр и tacacs+.

Например, если и транспорт, и протокол являются частью URL-адреса, и если формат транспорта правильный и он проверяется значением, предоставленным в регулярном выражении, тогда он возвращает true, даже если значение протокола недопустимо.

Java-код:

String pattern = "((?=.*;transport=(tcp|sctp|udp)\\b)|(?=.*;protocol=(diameter|radius|tacacs+)\\b))";
String url = "transport=tcp;protocol=aradius";
    Pattern regExPattern = Pattern.compile(pattern);
    if(regExPattern.matcher(url).find()) {
        return true;
    } else {
        return false;
    }

Это возвращает true, так как он успешно проверяет транспорт, но не может проверить значения протокола.


person ekansh    schedule 15.02.2020    source источник


Ответы (2)


Я не уверен на 100%, какие строки должны быть определены как действительные, но позвольте мне попытаться привести пример:

import java.util.regex.Pattern;

public class Main
{

    private static void check(String s,Pattern regExPattern)
    {
        boolean matches=regExPattern.matcher(s).matches();
        System.out.println(s);
        System.out.println("matches:"+regExPattern.matcher(s).matches()+", find:"+regExPattern.matcher(s).find());
        System.out.println();
    }

    public static void main(String[] args) throws Exception
    {
        String pattern = "((.+=.+;transport=(tcp|sctp|udp))||(.+=.+;protocol=(diameter|radius|tacacs\\+)))";
        Pattern regExPattern = Pattern.compile(pattern);

        check("transport=tcp;protocol=diameter", regExPattern);
        check("transport=udp", regExPattern);
        check("protocol=radius", regExPattern);
        check("other=other;protocol=radius", regExPattern);
        check("other=other;transport=sctp", regExPattern);
        check("wrong;protocol=tacacs+", regExPattern);
        check("wrong;transport=tcp", regExPattern);
        check("wrong;wrong", regExPattern);
        check("something else;transport=tcp;protocol=diameter;something else", regExPattern);
    }
}

Выходы:

transport=tcp;protocol=diameter
matches:true, find:true

transport=udp
matches:false, find:true

protocol=radius
matches:false, find:true

other=other;protocol=radius
matches:true, find:true

other=other;transport=sctp
matches:true, find:true

wrong;protocol=tacacs+
matches:false, find:true

wrong;transport=tcps
matches:false, find:true

wrong;wrong
matches:false, find:true

something else;transport=tcp;protocol=diameter;something else
matches:false, find:true

Я заменил ? на .+, потому что ? соответствует только одному символу, а .+ соответствует более чем одному символу. Тогда вы можете использовать match() вместо find().

match() требует, чтобы вся строка соответствовала шаблону. find() требует, чтобы только часть строки соответствовала части шаблона. Я думаю, вы хотели, чтобы соответствовать (не найти).

Я заменил .* на .+, потому что .* соответствует любому количеству символов (включая ноль), но я предполагаю, что вы хотите, чтобы здесь соответствовал хотя бы один символ.

Я удалил \\b, потому что он буквально соответствует символу b, который кажется не тем, что вам нужно.

Я заменил tacacs+ на tacacs\\+, потому что вы хотели сопоставить + буквально, не сопоставляя все слова, начинающиеся с tacacs, и любое количество s, например tacacsssssss.

Веб-сайт https://regex101.com/ очень полезен для тестирования регулярного выражения, поскольку он помечает части шаблона с помощью цвета и объясняет, что означают части.

Вместо того, чтобы использовать сложные выражения, которые вы не понимаете, вы можете проверить две части по отдельности, а затем написать оператор if (matches || matches2)..., который проверяет, соответствует ли хотя бы одно из них:

import java.util.regex.Pattern;

public class Main
{

    private static void check(String s, String pattern1, String pattern2)
    {
        System.out.println(s);
        boolean matches1 = s.matches(pattern1);
        boolean matches2 = s.matches(pattern2);
        if (matches1 || matches2)
        {
            System.out.println("matches");
        }
        else
        {
            System.out.println("does not match");
        }
    }

    public static void main(String[] args) throws Exception
    {
        String pattern1 = ".*;transport=(tcp|sctp|udp).*";
        String pattern2 = ".*;protocol=(diameter|radius|tacacs\\+).*";

        check("transport=tcp;protocol=diameter", pattern1, pattern2);
        check("transport=udp", pattern1, pattern2);
        check("protocol=radius", pattern1, pattern2);
        check("other=other;protocol=radius", pattern1, pattern2);
        check("other=other;transport=sctp", pattern1, pattern2);
        check("wrong;protocol=tacacs+", pattern1, pattern2);
        check("wrong;transport=tcp", pattern1, pattern2);
        check("wrong;wrong", pattern1, pattern2);
        check("something else;transport=tcp;protocol=diameter;something else", pattern1, pattern2);
    }
}

Выходы:

transport=tcp;protocol=diameter
matches
transport=udp
does not match
protocol=radius
does not match
other=other;protocol=radius
matches
other=other;transport=sctp
matches
wrong;protocol=tacacs+
matches
wrong;transport=tcp
matches
wrong;wrong
does not match
something else;transport=tcp;protocol=diameter;something else
matches
person Stefan    schedule 15.02.2020

Сложность заключается в том, что и транспорт, и протокол являются необязательными и появляются в любом порядке. Чтобы сделать это в одном регулярном выражении, у меня есть чередование с использованием |, где в первом варианте сначала сканируется параметр транспорта, а параметр протокола является необязательным, а во втором варианте все меняется на противоположное. Чтобы реализовать необязательное регулярное выражение A, которое может появляться далеко во входном потоке, мой подход заключается в использовании:

(.*(?<tag>A)|) Если во входном потоке появляется регулярное выражение A, сканируйте символы A, иначе не сканируйте символы. Но в любом случае совпадение есть.

Вы не можете использовать:

.*(?<tag>A)?, потому что механизм регулярных выражений удовлетворяет этому тривиально, сканируя 0 символов и никогда не сканируя A.

Регулярное выражение:

;transport=(?<transport1>tcp|sctp|udp)\b(.*;protocol=(?<protocol1>diameter|radius|tacacs+)\b|)|;protocol=(?<protocol2>diameter|radius|tacacs+)\b(.*;transport=(?<transport2>tcp|sctp|udp)\b|)

Посмотреть демонстрацию регулярного выражения

Программа:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Test
{
    public static void main(String[] args) {
        String tests[] = {
            "aaa;transport=tcp  ;protocol=radius",
            "aaa;protocol=diameter    ;transport=udp",
            "aaa;transport=sctp",
            "aaa;protocol=tacacs",
            "aaaa"
        };
        for (String test: tests) {
            Pattern pattern = Pattern.compile(";transport=(?<transport1>tcp|sctp|udp)\\b(.*;protocol=(?<protocol1>diameter|radius|tacacs+)\\b|)|;protocol=(?<protocol2>diameter|radius|tacacs+)\\b(.*;transport=(?<transport2>tcp|sctp|udp)\\b|)");
            System.out.println(test);
            Matcher m = pattern.matcher(test);
            if (m.find()) {
                String protocol = m.group("protocol1") == null ? m.group("protocol2") :  m.group("protocol1");
                String transport = m.group("transport1") == null ? m.group("transport2") : m.group("transport1");
                if (protocol != null) {
                    System.out.println("   protocol=" + protocol);
                }
                if (transport != null) {
                    System.out.println("   transport=" + transport);
                }
            }
        }
    }
}

Отпечатки:

aaa;transport=tcp  ;protocol=radius
   protocol=radius
   transport=tcp
aaa;protocol=diameter    ;transport=udp
   protocol=diameter
   transport=udp
aaa;transport=sctp
   transport=sctp
aaa;protocol=tacacs
   protocol=tacacs
aaaa

Примечание

Было бы проще использовать два отдельных регулярных выражения и два вызова find для сканирования значений транспорта и протокола. По крайней мере, регулярные выражения были бы намного проще.

person Booboo    schedule 15.02.2020