Все перекрывающиеся подстроки, соответствующие регулярному выражению Java
Есть ли метод API, который возвращает все (возможно, перекрывающиеся) подстроки, которые соответствуют регулярному выражению?
Например, у меня есть текстовая строка:String t = 04/31 412-555-1235;
и у меня есть шаблон:Pattern p = new Pattern("\\d\\d+");
это соответствует строкам из двух или более символов.
Матчи, которые я получаю: 04, 31, 412, 555, 1235.
Как получить совпадающие спички?
Я хочу вернуть код: 04, 31, 41, 412, 12, 55, 555, 55, 12, 123, 1235, 23, 235, 35.
Теоретически это должно быть возможно - есть очевидноеO(n^2)
алгоритм, который перечисляет и проверяет все подстроки по шаблону.
EDIT
Вместо перечисления всех подстрок безопаснее использоватьregion(int start, int end)
метод вMatcher
, Проверка шаблона по отдельной, извлеченной подстроке может изменить результат совпадения (например, если в начале / конце шаблона есть не захватывающая группа или проверка границы слова).
EDIT 2
На самом деле неясно, является лиregion()
делает то, что вы ожидаете для совпадений с нулевой шириной. Спецификация нечеткая, и эксперименты дают неутешительные результаты.
Например:
String line = "xx90xx";
String pat = "\\b90\\b";
System.out.println(Pattern.compile(pat).matcher(line).find()); // prints false
for (int i = 0; i < line.length(); ++i) {
for (int j = i + 1; j <= line.length(); ++j) {
Matcher m = Pattern.compile(pat).matcher(line).region(i, j);
if (m.find() && m.group().size == (j - i)) {
System.out.println(m.group() + " (" + i + ", " + j + ")"); // prints 90 (2, 4)
}
}
}
Я не уверен, какое самое элегантное решение. Один из подходов состоит в том, чтобы взять подстрокуline
и добавьте соответствующие граничные символы, прежде чем проверять,pat
Матчи.
EDIT 3
Вот полное решение, которое я придумал. Он может обрабатывать шаблоны нулевой ширины, границы и т. Д. В исходном регулярном выражении. Он просматривает все подстроки текстовой строки и проверяет, соответствует ли регулярное выражение только в определенной позиции, дополняя шаблон соответствующим количеством символов подстановки в начале и конце. Похоже, что это работает для случаев, которые я пробовал - хотя я не проводил обширного тестирования. Это, безусловно, менее эффективно, чем могло бы быть.
public static void allMatches(String text, String regex)
{
for (int i = 0; i < text.length(); ++i) {
for (int j = i + 1; j <= text.length(); ++j) {
String positionSpecificPattern = "((?<=^.{"+i+"})("+regex+")(?=.{"+(text.length() - j)+"}$))";
Matcher m = Pattern.compile(positionSpecificPattern).matcher(text);
if (m.find())
{
System.out.println("Match found: \"" + (m.group()) + "\" at position [" + i + ", " + j + ")");
}
}
}
}
EDIT 4
Вот лучший способ сделать это:https://stackoverflow.com/a/11372670/244526
EDIT 5
JRegex библиотека поддерживает поиск всех перекрывающихся подстрок, соответствующих регулярному выражению Java (хотя, как представляется, в последнее время оно не обновлялось). В частности,документация по непрерывному поиску определяет:
Using non-breaking search you can finding all possible occureneces of a pattern, including those that are intersecting or nested. This is achieved by using the Matcher's method proceed() instead of find()