¿Existe un método API que devuelva todas las subcadenas (posiblemente superpuestas) que coincidan con una expresión regular?Todas las subcadenas superpuestas que coincidan con una expresión regular java
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 consigo la superposición de partidos?
Quiero el código para volver: 04, 31, 41, 412, 12, 55, 555, 55, 12, 123, 1235, 23, 235, 35.
En teoría debería ser posible - hay un algoritmo obvio O(n^2)
que enumera y comprueba todas las subcadenas contra el patrón.
EDITAR
En lugar de enumerar todas las subcadenas, es más seguro utilizar el método region(int start, int end)
en Matcher
. Verificar el patrón contra una subcadena separada y extraída puede cambiar el resultado de la coincidencia (por ejemplo, si hay un grupo no captor o una verificación de límite de palabras al inicio/final del patrón).
EDIT 2
En realidad, no está claro si region()
hace lo que se puede esperar de partidos 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 es. Un enfoque sería tomar una subcadena de line
y rellenar con los caracteres de límite apropiados antes de verificar si el pat
coincide.
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 al rellenar el patrón con el número apropiado de comodines al principio y al final. Parece que funciona para los casos que probé, aunque no he hecho pruebas exhaustivas. Sin duda es 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 forma de hacer esto: https://stackoverflow.com/a/11372670/244526
EDITAR 5
La biblioteca JRegex apoya la búsqueda de todas las subcadenas superpuestas que coincidan con una expresión regular de Java (aunque parece que no se ha actualizado en un momento).En concreto, el documentation on non-breaking search especifica:
Uso de la búsqueda de no separación se puede encontrar todas las posibles occureneces de un patrón , incluyendo aquellos que se cruzan o anidado. Esto es logrado mediante el método de Matcher proceda() en lugar de encontrar()
acaba de hacer un bucle post-regex a través de los 3 o más resultados de caracteres –
http://regexlib.com/ podría ser un buen lugar para hacer algunas excavaciones. –
@ Ωmega Hago todo lo posible, pero estoy abierto a comentarios que no son útiles. Aclamaciones. –