2010-04-19 14 views
15

Vorrei rimuovere tutti i caratteri UTF-8 non validi da una stringa in JavaScript. Ho provato con questo JavaScript:Come rimuovere caratteri UTF-8 non validi da una stringa JavaScript?

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

Sembra che la convalida regex UTF-8 descritto qui (link rimosso) è più completo e ho adattato allo stesso modo come:

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");

Entrambi questi pezzi di codice sembrano essere consentendo valido UTF-8 a, ma non sono filtrando quasi nessuna delle cattive caratteri UTF-8 dal mio dati di test: UTF-8 decoder capability and stress test. O i caratteri non validi vengono visualizzati invariati o sembrano essere stati rimossi alcuni dei loro byte creando un nuovo carattere non valido.

Non ho molta familiarità con lo standard UTF-8 o con multibyte in JavaScript, quindi non sono sicuro di non rappresentare correttamente l'UTF-8 nella regex o se sto applicando l'espressione regolare di regex in JavaScript.

Modifica: aggiunta la bandiera globale alla mia espressione regolare per commento di Tomalak - tuttavia questo non funziona ancora per me. Sto abbandonando lo fare sul lato client per commento di Bobince.

+0

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

risposta

15

Le stringhe JavaScript sono nativamente Unicode. Contengono sequenze di caratteri * non sequenze di byte, quindi è impossibile per uno contenere una sequenza di byte non valida.

(Tecnicamente, in realtà contengono UTF-16 sequenze di unità di codice, che non è proprio la stessa cosa, ma questo probabilmente non è tutto ciò che è necessario preoccuparsi di questo momento.)

È possibile, se si è necessario, per qualche motivo, creare una stringa contenente caratteri usati come segnaposto per byte. vale a dire. utilizzando il carattere U+0080 ('\ x80') per indicare il byte 0x80. Questo è ciò che otterresti se codificassi i caratteri in byte usando UTF-8, quindi li decodificassi di nuovo ai caratteri usando per errore ISO-8859-1. C'è uno speciale linguaggio JavaScript per questo:

e di tornare da UTF-8 pseudobytes a personaggi ancora:

var characters= decodeURIComponent(escape(bytelike)); 

(Questo è, in particolare, praticamente l'unica volta che il escape/Le funzioni unescape devono essere sempre utilizzate e la loro esistenza in qualsiasi altro programma è quasi sempre un bug.

decodeURIComponent(escape(bytes)), poiché si comporta come un decoder UTF-8, genera un errore se la sequenza di unità di codice immesse in esso non è accettabile come byte UTF-8.

È molto raro che sia necessario lavorare su stringhe di byte come questa in JavaScript. Meglio continuare a lavorare in modo nativo in Unicode dal lato client. Il browser si prenderà cura della codifica UTF-8 della stringa sul filo (in una sottomissione di modulo o XMLHttpRequest).

+1

Grazie per una risposta informativa - essenzialmente che quello che sto facendo è difficile perché non dovrei farlo. Sto avendo problemi con certi personaggi sul back-end e ho bisogno di affrontarlo lì. –

+0

La stringa '" \ uD800 "' non è valida e causerà il lancio di 'encodeURIComponent'. – OrangeDog

+0

@OrangeDog: sì, poiché non esiste una rappresentazione UTF-8 di quella sequenza di unità di codice. – bobince

5

semplice errore, grande effetto:

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

senza il flag "globale", la sostituzione avviene solo per la prima partita.

Nota a margine: per rimuovere qualsiasi carattere che non adempia un qualche tipo di condizione complessa, come cadere in una serie di certo carattere Unicode gamme, è possibile utilizzare lookahead negativo:

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

dove re legge come

 
(?!  # 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

Grazie, che era un grosso difetto nel mio codice. Sfortunatamente, con la bandiera globale ora in posizione, entrambe le espressioni regolari che ho postato sembrano filtrare tutto ciò che non è ASCII. Il primo test dei dati di "stress test" è un testo UTF-8 valido che viene sottoposto a stripping e, se prendo del testo campione da http://www.columbia.edu/kermit/utf8.html, vengono rimossi tutti tranne ASCII. –

2

Mi sono imbattuto in questo problema con un risultato davvero strano dai dati Data Take di un'immagine digitale. Il mio scenario è certamente unico - utilizzando Windows Scripting Host (WSH) e l'oggetto ActiveX Shell.Application che permette di ottenere l'oggetto dello spazio dei nomi di una cartella e chiamare la funzione GetDetailsOf per restituire essenzialmente i dati exif dopo che è stato analizzato dal sistema operativo.

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

In windws Vista e 7, il risultato si presentava così:

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

Quindi il mio approccio è stato il seguente:

 
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]; 
} 

Il risultato, naturalmente, è una stringa che esclude quei caratteri del punto interrogativo.

So che sei andato con una soluzione diversa del tutto, ma ho pensato di postare la mia soluzione nel caso in cui qualcun altro ha problemi con questo e non può utilizzare un approccio linguistico lato server.

18

Io uso questo semplice e robusta approccio:

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

In pratica tutto quello che vuole veramente sono i caratteri ASCII 0-127 quindi basta ricostruire il char stringa char. Se è un buon salmerino, tienilo - se no, lascia perdere. Abbastanza robusto e se il risanamento è il tuo obiettivo, è abbastanza veloce (in effetti è molto veloce).

+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: '' input) .join (''); ' –

+1

One-liner senza ramda:' const cleanString = input => Array.of (input) .map (char => char.charCodeAt (0) <= 127? Char: '', input). join ('') ' – docodemore

4

Se stai cercando di rimuovere il "carattere non valido" - - da stringhe javascript allora si può sbarazzarsi di loro in questo modo:

myString = myString.replace(/\uFFFD/g, '') 
Problemi correlati