2010-04-19 68 views
15

Me gustaría eliminar todos los caracteres UTF-8 no válidos de una cadena en JavaScript. He intentado con este JavaScript:Cómo eliminar caracteres inválidos UTF-8 de una cadena de JavaScript?

strTest = strTest.replace(/([\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})|./g, "$1");

Parece que la validación de expresiones regulares UTF-8 describe aquí (enlace eliminado) es más completa y adaptada de la misma manera como:

strTest = strTest.replace(/([\x09\x0A\x0D\x20-\x7E]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})|./g, "$1");

Ambas piezas de código parecen estar permitiendo UTF-8 a través válida, pero no están filtrando casi ninguno de los malos UTF-8 caracteres de mi datos de prueba: UTF-8 decoder capability and stress test. O bien los caracteres incorrectos aparecen sin cambios o parecen tener algunos de sus bytes eliminados creando un nuevo carácter no válido.

No estoy muy familiarizado con el estándar UTF-8 o con multibyte en JavaScript, así que no estoy seguro de si estoy fallando en representar el UTF-8 correcto en la expresión regular o si estoy aplicando esa expresión regular incorrectamente en JavaScript

Editar: agregada la bandera global a mi expresión regular por comentario de Tomalak, sin embargo, esto todavía no funciona para mí. Estoy abandonando esto en el lado del cliente por cada comentario de Bobince.

+0

eslabones perdidos: enlace 1 - http: // stackoverflow.com/questions/1401317/remove-non-uft8-characters-from-string link 2 - http://www.w3.org/International/questions/qa-forms-utf-8 –

Respuesta

15

Las cadenas de JavaScript son nativamente Unicode. Tienen secuencias de caracteres * no secuencias de bytes, por lo que es imposible que contengan una secuencia de bytes no válida.

(Técnicamente, que en realidad contienen UTF-16 secuencias de código de unidad, que no es exactamente lo mismo, pero esto probablemente no es algo que tiene que preocuparse por ahora.)

Usted puede, si lo Por alguna razón, necesita crear una cadena que contenga caracteres utilizados como marcadores de posición para bytes. es decir. usando el caracter U+0080 ('\ x80') para representar el byte 0x80. Esto es lo que obtendrías si codificaras caracteres a bytes usando UTF-8, y luego los decodificaría por caracteres usando ISO-8859-1 por error. Hay un lenguaje especial JavaScript para esto:

y para volver de UTF-8 pseudobytes a personajes de nuevo:

var characters= decodeURIComponent(escape(bytelike)); 

(Esto es, sobre todo, más o menos la única vez que el escape/unescape funciones alguna vez deben utilizarse. Su existencia en cualquier otro programa es casi siempre un error.)

decodeURIComponent(escape(bytes)), ya que se comporta como un decodificador UTF-8, generará un error si la secuencia de unidades de código introducidas en ella no sería aceptable como bytes UTF-8.

Es muy raro que necesite trabajar en cadenas de bytes como esta en JavaScript. Es mejor seguir trabajando de forma nativa en Unicode en el lado del cliente. El navegador se encargará de UTF-8-codificación de la cadena en el cable (en un envío de formulario o XMLHttpRequest).

+1

Gracias por una respuesta informativa, esencialmente porque lo que estoy haciendo es difícil porque no debería hacerlo. Tengo problemas con ciertos personajes en el back-end, y necesito abordarlo allí. –

+0

La cadena '" \ uD800 "' no es válida, y hará que 'coddeURIComponent' lance. – OrangeDog

+0

@OrangeDog: sí, ya que no hay representación UTF-8 de esa secuencia de unidades de código. – bobince

5

error simple, gran efecto:

strTest = strTest.replace(/your regex here/g, "$1"); 
// ----------------------------------------^ 

sin la bandera "global", la sustitución se produce solamente durante el primer partido.

Nota al margen: Para eliminar cualquier carácter que no cumple algún tipo de afección compleja, como caer en un conjunto de cierto carácter Unicode rangos, puede utilizar búsqueda negativa hacia delante:

var re = /(?![\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})./g; 
strTest = strTest.replace(re, "") 

donde re lee como

 
(?!  # negative look-ahead: a position *not followed by*: 
    […] # any allowed character range from above 
)  # end lookahead 
.  # match this character (only if previous condition is met!) 
+0

Gracias, eso fue un gran error en mi código. Desafortunadamente, con la bandera global ahora en su lugar, las dos expresiones regulares que publiqué parecen filtrar cualquier cosa que no sea ASCII. La primera prueba de los datos de "stress test" es algún texto UTF-8 válido que se está eliminando, y si tomo texto de ejemplo de http://www.columbia.edu/kermit/utf8.html todo lo que no sea ASCII se eliminará. –

2

Me encontré con este problema con un resultado realmente extraño a partir de los datos de Fecha de toma de una imagen digital. Mi escenario es sin dudas único: usando Windows scripting host (wsh) y el objeto Shell.Application activex que permite obtener el objeto de espacio de nombres de una carpeta y llamar a la función GetDetailsOf para devolver esencialmente datos exif después de que el sistema operativo los haya analizado.

 
var app = new ActiveXObject("Shell.Application"); 
var info = app.Namespace("c:\"); 
var date = info.GetDetailsOf(info.ParseName("testimg.jpg"), 12); 

En windws Vista y 7, el resultado era la siguiente:

?8/?27/?2011 ??11:45 PM

Así que mi enfoque era la siguiente:

 
var chars = date.split(''); //split into characters 
var clean = ""; 
for (var i = 0; i < chars.length; i++) { 
    if (chars[i].charCodeAt(0) < 255) clean += chars[i]; 
} 

El resultado, por supuesto, es una cadena que excluye esos caracteres de interrogación.

Sé que se fue con una solución diferente por completo, pero pensé que publicaría mi solución en caso de que alguien más tenga problemas con esto y no pueda utilizar un enfoque de lenguaje del lado del servidor.

18

que utilizan este enfoque simple y robusto:

function cleanString(input) { 
    var output = ""; 
    for (var i=0; i<input.length; i++) { 
     if (input.charCodeAt(i) <= 127) { 
      output += input.charAt(i); 
     } 
    } 
    return output; 
} 

Básicamente todo lo que realmente quiere son los caracteres ASCII 0-127 por lo que sólo reconstruir la cadena de carbón de carbón. Si es un buen char, guárdelo, si no, deshágase de él. Bastante robusto y si su objetivo es el saneamiento, es lo suficientemente rápido (de hecho, es muy rápido).

+3

output + = input.charCodeAt (i) <= 127? input.charAt (i): '' – user40521

+0

One-liner con ramda: 'const cleanString = input => R.map (char => char.charCodeAt (0) <= 127? char: '', entrada) .join (''); ' –

+1

Trazador de líneas sin ramda:' const cleanString = input => Matriz.de (entrada) .map (char => char.charCodeAt (0) <= 127? Char: '', entrada). join ('') ' – docodemore

4

Si usted está tratando de eliminar el "carácter no válido" - - a partir de cadenas de Javascript a continuación, usted puede deshacerse de ellos de esta manera:

myString = myString.replace(/\uFFFD/g, '') 
Cuestiones relacionadas