Ниже приведен мой код:
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
объяснение: во втором примере находится 1.1.1 My
, что верно согласно <whatever characters><any number><dot><any number><dot><any number><single or double space><whatever characters>
, если только <whatever characters>
не содержит пробелов, точек и цифр.
Вы можете просто использовать шаблон с пробелом (\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. В середине даже пробелов нет.
В зависимости от того, нужно ли вам просто найти совпадающие строки или вы действительно хотите работать с найденной частью, вам придется дополнительно скорректировать свой шаблон, но поскольку вы не указали свои потребности более подробно, это следует задать с другим вопросом - если это вообще необходимо.
Давайте сначала посмотрим, чему соответствует шаблон:
Примените это к первой строке 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\.
не соответствует.
Примечание Есть несколько проблем с вашими требованиями к шаблону и вашим регулярным выражением. (Также указано другими)
<any number><dot><any number><dot><any number>
, но ваше регулярное выражение будет соответствовать только <any number><dot><any number><dot><any digit>
. Значит, не совпадет 2.5.12
. Используйте [0-9]+
или \\d+
, если хотите сопоставить любое число.<single or double space>
, но ваше регулярное выражение также будет соответствовать более чем двум пробелам после последней цифры. Чтобы сопоставить один или два пробела, используйте \\s{1,2}
вместо \\s+
.Спасибо другим ответам, прежде чем ответить на мой собственный вопрос. Наконец, я использовал следующее регулярное выражение:
Pattern anyServicePattern = Pattern.compile("[0-9a-zA-Z\\s]+((\\d+\\.){2}\\d+){1}\\s+[a-zA-Z]+");
Мне показалось, что другим это легко понять, и это решило некоторые другие крайние случаи, такие как "Other String9.3.1 My Other Strings
".
Используйте
(?<!\d\.)(?:\d+\.){2}[0-9]\s+[a-zA-Z]+
в качестве регулярного выражения