Регулярное выражение для проверки 3 повторяющихся символов - PullRequest
0 голосов
/ 17 мая 2018

Я пытаюсь подтвердить пароль, который не должен позволять 3 повторяющихся символа независимо от их положения в строке.

Например:

121121 - Не принимается, поскольку 1 появляется более 3 раз.

121212 - принято, поскольку 1 и 2 появляются только 3 раза

Я пробовал это

([0-9])\1{2,}

Но это подтверждают только последовательные повторяющиеся цифры.

Ответы [ 4 ]

0 голосов
/ 18 мая 2018

Регулярное решение для этого очень неэффективно .Пожалуйста, рассмотрите этот ответ из чисто академического интереса.

Шаблон, в котором отсутствуют строки, имеющие 4 или более экземпляров одного и того же символа:

^(?!.*(.).*\1.*\1.*\1).*

Последний .* может быть заменен наболее узкий паттерн, если вам нужно уточнить этот паттерн.

См. демонстрацию regex .

Основная часть здесь - это (?!.*(.).*\1.*\1.*\1) отрицательный прогноз.Он соответствует любым 0+ символам (если используется Pattern.DOTALL, любому символу, включая символы новой строки), как можно большему числу, затем он сопоставляется и захватывает (.)) любого символа в Группу 1, а затемсоответствует любым 0+ символам, за которыми следует один и тот же символ 3 раза.Если шаблон найден (сопоставлен), сопоставление всей строки завершится неудачно.

Почему он неэффективен? Шаблон в значительной степени зависит от возврата..* захватывает все символы до конца строки, затем двигатель возвращается назад, пытаясь разместить некоторый текст для последующих подшаблонов.Вы можете увидеть шаги по возврату сюда .Чем больше .*, тем более ресурсоемкий шаблон.

Почему ленивый вариант не лучше? ^(?!.*?(.).*?\1.*?\1.*?\1).* выглядит быстрее с некоторыми строками, иэто будет быстрее, если повторяющиеся символы появляются рядом друг с другом и началом строки.Если они находятся в конце строки, эффективность будет снижаться.Таким образом, если предыдущее регулярное выражение совпадает с 121212 за 77 шагов, то текущее также выполнит то же количество шагов.Однако, если вы проверите его с 1212124444, вы увидите, что ленивый вариант потерпит неудачу после 139 шагов , а жадный вариант потерпит неудачу после 58 шагов .И наоборот, 4444121212 приведет к сбою отложенного регулярного выражения, 14 шагов против 211 шагов с жадным вариантом .

В Java вы можете использоватьэто

s.matches("(?!.*(.).*\\1.*\\1.*\\1)")

или

s.matches("(?!.*?(.).*?\\1.*?\\1.*?\\1)")

Используйте решение Джейкоба в производстве.

0 голосов
/ 17 мая 2018

Я не рекомендую использовать регулярные выражения для чего-то подобного, так как было бы проще просто собрать пароль в Map, где ведется подсчет каждого символа.Затем вы можете просто проверить, существует ли какой-либо символ со счетом, превышающим 3:

password.chars()
        .boxed()
        .collect(Collectors.groupingBy(i -> i, Collectors.counting()))
        .values()
        .stream()
        .anyMatch(i -> i > 3);

. Возвращается true, если в password существует какой-либо символ, который выглядит больше 3 раз и false в противном случае.

0 голосов
/ 17 мая 2018

Используйте регулярное выражение с отрицательным взглядом вперед с обратной ссылкой:

boolean ok = str.matches("((.)(?!(.*\\2){3}))+");

См. демоверсия .

В английском языке это регулярное выражение говорит, что «каждый символ не должен появляться еще 3 раза после себя».

0 голосов
/ 17 мая 2018

Можете ли вы использовать карту вместо

public static void main(String[] args) {
    System.out.println(validate("121121"));
    System.out.println(validate("121212"));
}

static boolean validate(String s)
{
    HashMap<Character, Integer> map = new HashMap<>();
    for (Character c : s.toCharArray())
    {
        if (map.containsKey(c))
        {
            map.put(c, map.get(c) + 1 );
        }
        else
        {
            map.put(c , 1);
        }
    }

    for (Integer count : map.values())
    {
        if (count > 3)
            return false;
    }
    return true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...