Ya no tienes que indagar más por todo internet porque llegaste al espacio justo, contamos con la respuesta que quieres hallar pero sin complicaciones.
Solución:
Estoy muy sorprendido de que nadie haya respondido a esto. Puede usar el navegador mismo para hacer el escape por usted. Ninguna expresión regular es mejor o más segura que dejar que el navegador haga lo que mejor hace, manejar HTML.
function escapeHTML(str)
var p = document.createElement("p");
p.appendChild(document.createTextNode(str));
return p.innerHTML;
o una alternativa corta usando el constructor Option ()
function escapeHTML(str)
return new Option(str).innerHTML;
(Consulte más abajo para obtener una respuesta a la pregunta actualizada por los comentarios del OP a continuación)
¿Se puede manejar esto con HTML DOM y javascript?
No, una vez que el texto está en el DOM, el concepto de “escapar” no se aplica. El HTML texto de origen debe escaparse para que se analice correctamente en el DOM; una vez que está en el DOM, no se escapa.
Esto puede ser un poco complicado de entender, así que usemos un ejemplo. Aquí hay algo de HTML texto de origen (como en un archivo HTML que vería con su navegador):
This & That
Una vez que el navegador lo analiza en el DOM, el texto dentro del div es This & That
, porque el &
ha sido interpretado en ese punto.
Por lo tanto, deberá captar esto antes, antes de que el navegador analice el texto en el DOM. No puedes manejarlo después del hecho, es demasiado tarde.
Por separado, el string con el que estás empezando no es válido si tiene cosas como
en eso. Preprocesando ese inválido string será complicado. No puede simplemente usar funciones integradas de su entorno (PHP o lo que sea que esté usando en el lado del servidor) porque también escaparán de las etiquetas. Deberá procesar el texto, extraer solo las partes que desea procesar y luego ejecutarlas a través de un proceso de escape. Ese proceso será complicado. Un &
seguido de un espacio en blanco es bastante fácil, pero si hay entidades sin escape en el texto de origen, ¿cómo sabe si debe escapar de ellas o no? ¿Asume que si el string contiene &
, lo dejas solo? O conviértelo en &
? (Lo cual es perfectamente válido; así es como se muestra la string &
en una página HTML).
Lo que realmente necesita hacer es corregir el problema subyacente: lo que crea estas cadenas no válidas y medio codificadas.
Editar: De nuestro flujo de comentarios a continuación, la pregunta es totalmente diferente de lo que parecía en su ejemplo (eso no es un sentido crítico). Para recapitular los comentarios para quienes llegan a este nuevo, dijiste que obtenías estas cadenas de WebKit’s innerHTML
, y dije que era extraño, innerHTML
debería codificar &
correctamente (y le indicó un par de páginas de prueba que sugerían que sí). Tu respuesta fue:
Esto funciona para &. Pero la misma página de prueba no funciona para entidades como ©, ®, «y muchas más.
Eso cambia la naturaleza de la pregunta. Desea hacer entidades a partir de caracteres que, si bien son perfectamente válidos cuando se usan literalmente (siempre que tenga su codificación de texto correcta), podrían expresarse como entidades y, por lo tanto, hacerlos más resistentes a los cambios de codificación de texto.
Podemos hacerlo. Según la especificación, los valores de los caracteres en un JavaScript string son UTF-16 (utilizando Unicode Normalized Form C) y cualquier conversión de la codificación de caracteres de origen (ISO 8859-1, Windows-1252, UTF-8, lo que sea) se realiza antes de que el tiempo de ejecución de JavaScript lo vea. (Si no está 100% seguro de saber a qué me refiero con codificación de caracteres, vale la pena detenerse ahora y leer El mínimo absoluto que todo desarrollador de software debe conocer absoluta y positivamente sobre Unicode y conjuntos de caracteres (¡sin excusas!) por Joel Spolsky, luego regresando.) Así que ese es el lado de entrada. En el lado de la salida, las entidades HTML identifican puntos de código Unicode. Entonces podemos convertir de cadenas de JavaScript a entidades HTML de manera confiable.
Sin embargo, el diablo está en los detalles, como siempre. JavaScript asume explícitamente que cada valor de 16 bits es un carácter (consulte la sección 8.4 en la especificación), aunque eso no es realmente true de UTF-16: un valor de 16 bits puede ser un “sustituto” (como 0xD800) que solo tiene sentido cuando se combina con el siguiente valor, lo que significa que dos “caracteres” en JavaScript string son en realidad un personaje. Esto no es raro en los idiomas del Lejano Oriente.
Entonces un robusto conversión que comienza con JavaScript string y da como resultado que una entidad HTML no puede asumir que un “carácter” de JavaScript en realidad es igual a un carácter en el texto, tiene que manejar sustitutos. Afortunadamente, hacerlo es muy fácil porque las personas inteligentes que definen Unicode lo hicieron muy fácil: el primer valor sustituto siempre está en el rango 0xD800-0xDBFF (incluido), y el segundo sustituto siempre está en el rango 0xDC00-0xDFFF (incluido). Por lo tanto, cada vez que vea un par de “caracteres” en un JavaScript string que coinciden con esos rangos, se trata de un solo carácter definido por un par sustituto. Las fórmulas para convertir del par de valores sustitutos a un valor de punto de código se dan en los enlaces anteriores, aunque de forma bastante obtusa; Encuentro esta página mucho más accesible.
Armados con toda esta información, podemos escribir una función que tomará un JavaScript string y busque caracteres (caracteres reales, que pueden tener uno o dos “caracteres” de largo) que podría querer convertir en entidades, reemplazándolos con entidades con nombre de un mapa o entidades numéricas si no las tenemos en nuestro mapa con nombre:
// A map of the entities we want to handle.
// The numbers on the left are the Unicode code point values; their
// matching named entity strings are on the right.
var entityMap =
"160": " ",
"161": "¡",
"162": "cent;",
"163": "pound;",
"164": "curren;",
"165": "yen;",
"166": "brvbar;",
"167": "sect;",
"168": "uml;",
"169": "©",
// ...and lots and lots more, see http://www.w3.org/TR/REC-html40/sgml/entities.html
"8364": "€" // Last one must not have a comma after it, IE doesn't like trailing commas
;
// The function to do the work.
// Accepts a string, returns a string with replacements made.
function prepEntities(str) ), you want to leave
// alone, it searches for the surrogates. The second part of the alternation you can
// adjust as you see fit, depending on how conservative you want to be. The example
// below uses [u0000-u001fu0080-uFFFF], meaning that it will match and convert any
// character with a value from 0 to 31 ("control characters") or above 127 -- e.g., if
// it's not "printable ASCII" (in the old parlance), convert it. That's probably
// overkill, but you said you wanted to make entities out of things, so... :-)
return str.replace(/[uD800-uDBFF][uDC00-uDFFF]
Debería estar bien pasando todo el HTML a través de él, ya que si estos caracteres aparecen en attribute valores, es casi seguro que también desee codificarlos allí.
yo tengo no usé lo anterior en producción (de hecho, lo escribí para esta respuesta, porque el problema me intrigó) y es totalmente suministrado sin garantía de ningún tipo. He tratado de asegurarme de que maneja pares sustitutos porque eso es necesario para los idiomas del Lejano Oriente, y apoyarlos es algo que todos deberíamos estar haciendo ahora que el mundo se ha vuelto más pequeño.
Página de ejemplo completa:
Test Page
Copyright: © Yen: ¥ Cedilla: ¸ Surrogate pair: 𐀀
Allí he incluido la cedilla como un ejemplo de conversión a una entidad numérica en lugar de una nombrada (desde que dejé cedil
de mi mapa de ejemplo muy pequeño). Y tenga en cuenta que el par sustituto al final aparece en la primera alerta como dos “caracteres” debido a la forma en que JavaScript maneja UTF-16.