«1. Обзор

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

2. Использование регулярных выражений

Один из способов выполнить нашу проверку — использовать регулярные выражения. Чтобы ознакомиться с регулярными выражениями, ознакомьтесь с этой статьей.

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

private static final Pattern[] inputRegexes = new Pattern[4];

static {
    inputRegexes[0] = Pattern.compile(".*[A-Z].*");
    inputRegexes[1] = Pattern.compile(".*[a-z].*");
    inputRegexes[2] = Pattern.compile(".*\\d.*");
    inputRegexes[3] = Pattern.compile(".*[`[email protected]#$%^&*()\\-_=+\\\\|\\[{\\]};:'\",<.>/?].*");
}

Кроме того, мы должны создать простой метод, который мы собираемся использовать. чтобы проверить, соответствует ли наша строка условиям:

private static boolean isMatchingRegex(String input) {
    boolean inputMatches = true;
    for (Pattern inputRegex : inputRegexes) {
        if (!inputRegex.matcher(input).matches()) {
            inputMatches = false;
        }
    }
    return inputMatches;
}

2.1. Одно регулярное выражение

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


Таким образом, нам не понадобится статический блок для инициализации и компиляции всех наших множественных выражений. Кроме того, не было бы необходимости перебирать их все и находить, какие совпадают, а какие нет.

Все, что нам нужно сделать, это объявить наше регулярное выражение:

String regex = "^(?=.*?\\p{Lu})(?=.*?\\p{Ll})(?=.*?\\d)" +
    "(?=.*?[`[email protected]#$%^&*()\\-_=+\\\\|\\[{\\]};:'\",<.>/?]).*$";

А затем скомпилировать и сравнить его:

@Test
public void givenSingleRegex_whenMatchingCorrectString_thenMatches() {
    String validInput = "Ab3;";
    assertTrue(Pattern.compile(regex).matcher(validInput).matches());
}

Есть несколько вещей, которые мы должны отметить относительно нашего регулярного выражения.

Во-первых, мы использовали положительный просмотр вперед (?=X) для каждой группы символов. Это означает, что мы ожидаем, что X будет найден после начала строки (отмеченной ^), чтобы соответствовать, но мы не хотим идти в конец X, а хотим остаться в начале строки .


Еще одна вещь, которую следует отметить, это то, что на этот раз мы использовали не [A-Z] или [a-z] для буквенных групп, а вместо этого использовали \\p{Lu} и \\p{Ll}. Они будут соответствовать любому типу букв (в нашем случае прописных и строчных соответственно) на любом языке, а не только на английском.

3. Использование Core Java

Давайте теперь посмотрим, как мы можем выполнить ту же проверку, если мы не хотим использовать регулярные выражения. Мы воспользуемся преимуществами классов символов и строк и их методов, чтобы проверить, присутствуют ли в нашей строке все необходимые символы:

private static boolean checkString(String input) {
    String specialChars = "~`[email protected]#$%^&*()-_=+\\|[{]};:'\",<.>/?";
    char currentCharacter;
    boolean numberPresent = false;
    boolean upperCasePresent = false;
    boolean lowerCasePresent = false;
    boolean specialCharacterPresent = false;

    for (int i = 0; i < input.length(); i++) {
        currentCharacter = input.charAt(i);
        if (Character.isDigit(currentCharacter)) {
            numberPresent = true;
        } else if (Character.isUpperCase(currentCharacter)) {
            upperCasePresent = true;
        } else if (Character.isLowerCase(currentCharacter)) {
            lowerCasePresent = true;
        } else if (specialChars.contains(String.valueOf(currentCharacter))) {
            specialCharacterPresent = true;
        }
    }

    return
      numberPresent && upperCasePresent && lowerCasePresent && specialCharacterPresent;
}

Здесь следует отметить несколько вещей. Основная идея заключается в том, что мы перебираем нашу строку и проверяем, относятся ли ее символы к требуемым типам. Используя класс Character, мы можем легко проверить, является ли определенный символ цифрой, символом верхнего или нижнего регистра.

К сожалению, нет аналогичного метода, который бы сказал нам, имеем ли мы дело с одним из спецсимволов. Значит, нам нужен другой подход.

Мы создали строку, содержащую все необходимые нам специальные символы, а затем проверили, содержит ли она наш конкретный символ.


4. Заключение

В этой быстрой статье мы показали, как проверить, содержит ли строка требуемые символы. В первом сценарии мы использовали регулярные выражения, а во втором — основные классы Java.

Как обычно, полный исходный код можно найти на GitHub.