Quizás haya una forma más fácil de usar expresiones regulares en Java, pero yo no la encuentro. Usarlas en JavaScript, Python o Ruby es de las cosas que hacen atractivos estos lenguajes, pero en Java cuesta hacer natural lo natural.
Mi problematica es que tengo un servicio que retorna contenido HTML, y necesito dos cosas:
1. Saber cuantos caracteres del contenido pertenecen a TAGS HTML.
2. Retornar el contenido sin HTML, o sea en texto plano.
Por ejemplo, del texto:
"Presione <b><a href="javascript:void(0)">Aqui</a></b>..."
Debo retornar ["Presione Aqui", 40]. (40 es la cantidad de caracteres dentro de los tags).
Luce sencillo a simple vista, parsear el texto en busca de patrones que se corresponden con TAGS HTML substituyendo el patrón por un caracter blanco para eliminar los TAGS y contando el length de cada patrón devuelto. O sea se hace evidente el uso de Expresiones Regulares.
A continuación mi solución para que noten lo complicado que se hace programar con expresiones regulares en Java. Si alguien encuentra una forma más natural por favor no dude en enviarmela a través de un comentario.
…
Primero un contenedor de expresiones regulares compiladas
// regular expression Patterns (HTML TAGS) container
private static final Pattern[] HTML_TAG_REXP;
// init
static {
HTML_TAG_REXP = new Pattern[] {
Pattern.compile("<(a|A).*?>"),
Pattern.compile("</(a|A)>"),
Pattern.compile("<(b|B).*?>"),
Pattern.compile("</(b|B)>"),
Pattern.compile("<(i|I).*?>"),
Pattern.compile("</(i|I)>"),
Pattern.compile("<(p|P).*?>"),
Pattern.compile("</(p|P)>"),
Pattern.compile("<(img|IMG).*?>"),
Pattern.compile("</(img|IMG)>"),
Pattern.compile("<(stong|STRONG).*?>"),
Pattern.compile("</(strong|STRONG)>"),
Pattern.compile("<(h1|H1).*?>"),
Pattern.compile("</(h1|H1)>"),
Pattern.compile("<(h2|H2).*?>"),
Pattern.compile("</(h2|H2)>"),
Pattern.compile("<(h3|H3).*?>"),
Pattern.compile("</(h3|H3)>"),
};
}
Al compilarlas mejoramos la performance vs usar expresiones regulares literales. (Solo coloque algunos TAGS, pero basta con agregar más a la lista).
Y a continuación el método que pasado el contenido en HTML retorna un arreglo de objetos; donde en la primera posición va el contenido en texto plano (sin los TAGS HTML) y en la segunda posición la cantidad de caracteres que pertenecen a los TAGS.
...
/**
* @param content
* @return [String, Integer]
*/
private Object[] removeAndCountHtmlTags(String content) {
String result = content;
int htmlCharCount = 0;
for (int i = 0; i < HTML_TAG_REXP.length; i++) {
// create the matcher against the result
Matcher m = HTML_TAG_REXP[i].matcher(result);
// while send a message to find a match group is true
while (m.find()) {
LOG.info("matcher group - " + m.group(0));
// count the number of chars that match
// the group
htmlCharCount += m.group(0).length();
// replace first ocurrence (eliminate tags)
result = m.replaceFirst("");
// and send the message again to find the next
m = HTML_TAG_REXP[i].matcher(result);
}
}
return new Object[] {result, new Integer(htmlCharCount)};
}
...