Регулярное выражение Java не работает для этого особого случая использования

Ниже приведен мой код:

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

public class Main {
    public static void main(String args[]) {
        String pageText = "Other Strings 9.5.1 My Other Strings";
        String pageText2 = "Other Strings 9.3.1.1.1 My Other Strings";
        Pattern anyServicePattern = Pattern.compile("(\\d+\\.){2}[0-9]\\s+[a-zA-Z]+");
        Matcher anyServiceMatcher = anyServicePattern.matcher(pageText);
        if (anyServiceMatcher.find()) {
            System.out.println("Found");
        } else {
            System.out.println("Not Found");
        }
        
        Matcher anyServiceMatcher2 = anyServicePattern.matcher(pageText2);
        if (anyServiceMatcher2.find()) {
            System.out.println("Found");
        } else {
            System.out.println("Not Found");
        }
    }
}

Он печатает:
Найден
Найденный

Я хочу, чтобы это распечаталось
Найден
Не найдено

т. е. я хочу, чтобы регулярное выражение соответствовало шаблону <whatever characters><any number><dot><any number><dot><any number><single or double space><whatever characters>

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

Вот ссылка на jdoodle: https://www.jdoodle.com/ia/14IW

Используйте (?<!\d\.)(?:\d+\.){2}[0-9]\s+[a-zA-Z]+ в качестве регулярного выражения

anubhava 07.07.2024 20:09

объяснение: во втором примере находится 1.1.1 My, что верно согласно <whatever characters><any number><dot><any number><dot><any number><single or double space><whatever characters>, если только <whatever characters> не содержит пробелов, точек и цифр.

user85421 07.07.2024 20:49
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
76
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете просто использовать шаблон с пробелом (\s) слева, например (?i)\\s((?:\\d+\\.){2}\\d+)\\s+[a-z]:

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

public class Main {
    public static void main(String args[]) {
        String pageText = "Other Strings 9.5.1 My Other Strings";
        String pageText2 = "Other Strings 9.3.1.1.1 My Other Strings";
        Pattern anyServicePattern = Pattern.compile("(?i)\\s((?:\\d+\\.){2}\\d+)\\s+[a-z]");
        Matcher anyServiceMatcher = anyServicePattern.matcher(pageText);
        if (anyServiceMatcher.find()) {
            System.out.println("Found");
        } else {
            System.out.println("Not Found");
        }

        Matcher anyServiceMatcher2 = anyServicePattern.matcher(pageText2);
        if (anyServiceMatcher2.find()) {
            System.out.println("Found");
        } else {
            System.out.println("Not Found");
        }
    }
}

Принты

Found
Not Found

Подробности:

  • (?i): нечувствительный флаг.
  • \\s: один пробел перед версией.
  • ((?:\\d+\\.){2}\\d+): группа захвата, которая соответствует версиям с одной или несколькими цифрами (например, 1.121115.1, 121.1233.1121, ... 1212.1244.91221.
  • \\s+[a-z]: один или несколько пробелов и буква справа.

Проблема с вашим регулярным выражением заключается в том, что во втором случае оно просто соответствует «1.1.1 Мои другие строки», потому что ваш первый «любой символ» также включает «9.3». из второго текста.

Итак, чтобы оправдать ваши ожидания, я бы предложил один из этих двух вариантов:

  • сопоставьте пробел перед комбинацией числа и точки
  • добавить ноль с отрицательным просмотром назад

Космическое совпадение будет: \s(\d+\.){2}\d\s+[a-zA-Z]+

Вариант с нулем и отрицательным просмотром: (?!<\d\.)(\d+\.){2}\d\s+[a-zA-Z]+

Обратите внимание, что я не экранировал escape-символы, поэтому вы можете протестировать регулярные выражения и в другом месте (например, regex101.com), а также обратите внимание, что я заменил вашу последнюю часть классом символов для цифры \d, как вы использовали это раньше. .

Есть и другие потенциальные проблемы с вашим шаблоном — я не исправил их, но хочу предупредить вас:

  • Этот шаблон не будет напрямую соответствовать вашему описанию, поскольку вы написали, что он должен сначала соответствовать «любому символу», но совпадение начнется только после этой части, но будет включать последнюю часть «любого символа».

  • Последняя часть «любой символ» не является «любым символом», как вы ее написали — она соответствует только буквам верхнего и нижнего регистра от a до z. В середине даже пробелов нет.

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

Давайте сначала посмотрим, чему соответствует шаблон:

  1. (\d+\.) => группа, состоящая из любого числа, за которым следует точка
  2. {2} => дважды соответствует предыдущей группе
  3. [0-9] => любая цифра от 0 до 9
  4. \s+ => один или несколько пробелов
  5. [a-zA-Z] => любая заглавная или строчная буква алфавита

Примените это к первой строке Other Strings 9.5.1 My Other Strings, совпадение будет найдено в 9.5.1 My. Теперь примените это к вашей первой строке Other Strings 9.3.1.1.1 My Other Strings, совпадение будет найдено в 1.1.1 My. Вот почему вас находят в обоих случаях. Обратите внимание, что ни в одном из вышеперечисленных случаев вы не сопоставляете всю строку.

Решение: Если последовательность номеров всегда начинается с пробела, добавьте \s в начале шаблона.

\s(\\d+\\.){2}[0-9]\\s+[a-zA-Z]+

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

(?<!\\d\\.)(\\d+\\.){2}[0-9]\\s+[a-zA-Z]+

(?<!\\d\\.) представляет собой негативный просмотр назад нулевой ширины. Короче говоря, он утверждает, что шаблон \d\. не соответствует.

Примечание Есть несколько проблем с вашими требованиями к шаблону и вашим регулярным выражением. (Также указано другими)

  1. Ваше регулярное выражение соответствует не всему требуемому шаблону, а только его части.
  2. Вы сказали <any number><dot><any number><dot><any number>, но ваше регулярное выражение будет соответствовать только <any number><dot><any number><dot><any digit>. Значит, не совпадет 2.5.12. Используйте [0-9]+ или \\d+, если хотите сопоставить любое число.
  3. Вы сказали <single or double space>, но ваше регулярное выражение также будет соответствовать более чем двум пробелам после последней цифры. Чтобы сопоставить один или два пробела, используйте \\s{1,2} вместо \\s+.
  4. Что значит? Это буквенно-цифровой символ/пробелы/новая строка? Ваше регулярное выражение соответствует только буквам верхнего и нижнего регистра.
Ответ принят как подходящий

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

Pattern anyServicePattern = Pattern.compile("[0-9a-zA-Z\\s]+((\\d+\\.){2}\\d+){1}\\s+[a-zA-Z]+");  

Мне показалось, что другим это легко понять, и это решило некоторые другие крайние случаи, такие как "Other String9.3.1 My Other Strings".

Другие вопросы по теме