2009-03-10 20 views
7

Tengo un área de texto wysiwyg en una aplicación web Java. Los usuarios pueden ingresar texto, darle un estilo o pegar texto con formato HTML.Vincular texto con expresiones regulares en Java

Lo que estoy tratando de hacer es linkify el texto. Esto significa, convertir todas las URL posibles dentro del texto, a su "contraparte de trabajo", es decir, agregar < a href = "..."> ... </a>.

Esta solución funciona cuando todo lo que tengo es texto plano:

String r = "http(s)?://([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?"; 
Pattern pattern = Pattern.compile(r, Pattern.DOTALL | Pattern.UNIX_LINES | Pattern.CASE_INSENSITIVE); 
Matcher matcher = pattern.matcher(comment); 
comment = matcher.replaceAll("<a href=\"$0\">$0</a>"); // group 0 is the whole expression 

pero el problema es cuando hay algún texto ya formateado, es decir, que ya tiene la < a href =". .. "> ... </a> etiquetas.

por lo que estoy buscando alguna forma para el patrón no coincidir cada vez que encuentra el texto entre dos etiquetas HTML (< a>). He leído que esto se puede lograr con lookahead o lookbehind pero todavía no puedo hacerlo funcionar. Estoy seguro de que lo estoy haciendo mal porque la expresión regular aún coincide. Y sí, he estado jugando/depurando grupos, cambiando $ 0 a $ 1, etc.

¿Alguna idea?

+0

Me pregunto cuántas más preguntas sobre este tema son necesarias para que cada permutación del título ya exista en SO y la gente comience a usar una de las soluciones que ha sido resuelto previamente. – Tomalak

+1

Pasé mucho tiempo con este y realicé algunas investigaciones, pero todavía no podía entenderlo. El desbordamiento de la pila me ayudó a encontrar la solución y ahora toda la comunidad puede aprovechar estas respuestas. es impreciso y ofensivo. –

+0

también te desafío a que me muestres una solución a este problema que ya estaba en SO con un "título permutado" –

Respuesta

9

Usted está cerca. Puede utilizar una "búsqueda hacia atrás negativo" de esta manera:

(?<!href=")http:// etc 

Todos los resultados precedidos por href serán ignorados.

+0

gracias, era exactamente esto lo que necesitaba ... ¡estaba muy cerca! –

+0

Siempre llevo conmigo la "Referencia de bolsillo de expresión regular" ;-) –

0

Quizás el análisis html sea más apropiado para usted (htmlparser por ejemplo). Entonces podría tener nodos html y solo enlaces "linkify" en el texto y no en los atributos.

0

Si tiene que hacer su propia versión, al menos consulte los algoritmos/patrones utilizados en una implementación de Markdown de código abierto, por ejemplo, MarkdownJ.

1

Si quieres usar regex, (aunque creo que analizar primero en XML/HTML es más robusto) creo que mirar hacia adelante o hacia atrás tiene sentido. Un primer intento podría ser añadir esto al final de la expresión regular:

(?!</a>) 

Significado: no coinciden si hay un cierre de una etiqueta justo después. (Esto podría ser ajustado para siempre, por supuesto.) Esto no funciona bien, sin embargo, porque dada la cadena

<a href="...">http://example.com/</a> 

Esta expresión regular trata de hacer coincidir "http://example.com/", fallar debido a la búsqueda hacia delante (como esperamos), y luego retroceder el calificador codicioso para tener en el extremo y coincidir con "http://example.com" en su lugar, que no tiene una después de él.

Puede solucionar este problema utilizando un possessive qualifier en su +, * y? operadores - solo pega un + después de ellos. Esto les impide retroceder. Probablemente esto también sea bueno por motivos de rendimiento.

Esto funciona para mí (tenga en cuenta los tres adicional + 's):

String r = "http(s)?://([\\w+?\\.\\w+])++([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*+)?+(?!</a>)"; 
1

Si realmente quiere hacerlo con expresiones regulares, que:

String r = "(?<![=\"\\/>])http(s)?://([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?"; 

por ejemplo, compruebe que la URL no está siguiendo a = "o />

Cuestiones relacionadas