Todas las subcadenas superpuestas que coinciden con una expresión regular de Java
¿Existe un método de API que devuelva todas las subcadenas (posiblemente superpuestas) que coincidan con una expresión regular?
Por ejemplo, tengo una cadena de texto:String t = 04/31 412-555-1235;
, y tengo un patrón:Pattern p = new Pattern("\\d\\d+");
que coincide con cadenas de dos o más caracteres.
Los partidos que recibo son: 04, 31, 412, 555, 1235.
¿Cómo obtengo coincidencias superpuestas?
Quiero que el código regrese: 04, 31, 41, 412, 12, 55, 555, 55, 12, 123, 1235, 23, 235, 35.
Teóricamente debería ser posible, hay una obviaO(n^2)
Algoritmo que enumera y comprueba todas las subcadenas contra el patrón.
EDITAR
En lugar de enumerar todas las subcadenas, es más seguro usar elregion(int start, int end)
método enMatcher
. La comparación del patrón con una subcadena extraída y separada puede cambiar el resultado de la coincidencia (por ejemplo, si hay un grupo que no captura o una verificación de límite de palabra al inicio / final del patrón).
Editar 2
En realidad, no está claro siregion()
hace lo que esperas para coincidencias de ancho cero. La especificación es vaga, y los experimentos arrojan resultados decepcionantes.
Por ejemplo:
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)
}
}
}
No estoy seguro de cuál es la solución más elegante. Un enfoque sería tomar una subcadena deline
y rellene con los caracteres de contorno apropiados antes de comprobar si elpat
partidos.
EDITAR 3
Aquí está la solución completa que se me ocurrió. Puede manejar patrones de ancho cero, límites, etc. en la expresión regular original. Examina todas las subcadenas de la cadena de texto y comprueba si la expresión regular coincide solo en la posición específica rellenando el patrón con el número apropiado de comodines al principio y al final. Parece funcionar para los casos que probé, aunque no he realizado pruebas exhaustivas. Es ciertamente menos eficiente de lo que podría 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 + ")");
}
}
}
}
EDITAR 4
Aquí hay una mejor manera de hacer esto:https://stackoverflow.com/a/11372670/244526
EDITAR 5
losJRegex la biblioteca permite encontrar todas las subcadenas superpuestas que coincidan con una expresión regular de Java (aunque parece que no se ha actualizado en un tiempo). Específicamente, laDocumentación sobre la búsqueda sin interrupciones. especifica:
Mediante la búsqueda sin interrupciones, puede encontrar todas las posibles incidencias de un patrón, incluidas las que se intersecan o anidan. Esto se logra utilizando el método de Matcher proced () en lugar de find ()