Todos os substrings sobrepostos que correspondem a um java regex
Existe um método de API que retorna todas as substrings (possivelmente sobrepostas) que correspondem a uma expressão regular?
Por exemplo, eu tenho uma string de texto:String t = 04/31 412-555-1235;
e eu tenho um padrão:Pattern p = new Pattern("\\d\\d+");
que corresponde a sequências de dois ou mais caracteres.
Os jogos que recebo são: 04, 31, 412, 555, 1235.
Como faço para obter correspondências sobrepostas?
Quero que o código retorne: 04, 31, 41, 412, 12, 55, 555, 55, 12, 123, 1235, 23, 235, 35.
Teoricamente, isso deveria ser possível - há uma óbviaO(n^2)
Algoritmo que enumera e verifica todas as substrings em relação ao padrão.
EDITAR
Em vez de enumerar todas as substrings, é mais seguro usar oregion(int start, int end)
método emMatcher
. A verificação do padrão em relação a uma substring extraída separada pode alterar o resultado da correspondência (por exemplo, se houver um grupo de não captura ou uma verificação de limite de palavras no início / fim do padrão).
EDIT 2
Na verdade, não está claro seregion()
faz o que você espera para correspondências de largura zero. A especificação é vaga e os experimentos produzem resultados decepcionantes.
Por exemplo:
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)
}
}
}
Não tenho certeza qual é a solução mais elegante. Uma abordagem seria obter uma substring deline
e pad com os caracteres de limite apropriados antes de verificar se opat
fósforos.
EDITAR 3
Aqui está a solução completa que eu criei. Ele pode manipular padrões de largura zero, limites, etc. na expressão regular original. Ele examina todas as substrings da cadeia de texto e verifica se a expressão regular corresponde apenas à posição específica preenchendo o padrão com o número apropriado de curingas no início e no final. Parece funcionar para os casos que eu tentei - embora eu não tenha feito testes extensivos. É certamente menos eficiente do que poderia ser.
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
Aqui está uma maneira melhor de fazer isso:https://stackoverflow.com/a/11372670/244526
EDIT 5
oJRegex A biblioteca suporta a localização de todas as substrings sobrepostas que correspondam a um java regex (embora pareça não ter sido atualizado por algum tempo). Especificamente, odocumentação sobre pesquisa sem quebra especifica:
Usando a pesquisa sem quebra, você pode encontrar todas as ocorrências possíveis de um padrão, incluindo aquelas que estão se interceptando ou aninhadas. Isso é obtido usando o método do Matcher proceed () em vez de find ()