Как удалить недопустимые символы UTF-8 из строки JavaScript?
Я хотел бы удалить все недопустимые символы UTF-8 из строки в JavaScript. Я пробовал с этим JavaScript:
strTest = strTest.replace(/([\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})|./g, "$1");
Кажется, что описанное здесь регулярное выражение UTF-8 (ссылка удалена) более полная, и я адаптировал его так же, как:
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");
Оба этих фрагмента кода, по-видимому, позволяют использовать допустимый UTF-8, но не фильтруют практически любые из символов UTF-8 из моих тестовых данных: Возможности декодера UTF-8 и стресс-тест. Либо дурные символы проходят без изменений, либо, похоже, удаляются некоторые из их байтов, создавая новый, недопустимый символ.
Я не очень хорошо знаком с стандартом UTF-8 или с многобайтом в JavaScript, поэтому я не уверен, что я не могу представить правильный UTF-8 в регулярном выражении или если я неправильно применяю это регулярное выражение в JavaScript.
Изменить: добавлен глобальный флаг в мое регулярное выражение за комментарий Tomalak - однако это все еще не работает для меня. Я отказываюсь от этого делать на стороне клиента на комментарий bobince.
Ответы
Ответ 1
Я использую этот простой и прочный подход:
function cleanString(input) {
var output = "";
for (var i=0; i<input.length; i++) {
if (input.charCodeAt(i) <= 127) {
output += input.charAt(i);
}
}
return output;
}
В принципе, все, что вам действительно нужно, это символы ASCII 0-127, поэтому просто перестройте строку char на char. Если это хороший char, держите его - если нет, то это. Довольно надежный, и если санитария является вашей целью, она достаточно быстро (на самом деле она очень быстро).
Ответ 2
Строки JavaScript являются естественными Unicode. Они содержат последовательности символов *, а не байтовые последовательности, поэтому невозможно содержать недопустимую последовательность байтов.
(Технически они фактически содержат последовательности кода кода UTF-16, что не совсем то же самое, но это, вероятно, не то, о чем вам нужно беспокоиться прямо сейчас.)
Вы можете, если вам по какой-то причине, создать строку, содержащую символы, используемые в качестве заполнителей для байтов. то есть. используя символ U+0080
('\ x80'), чтобы стоять за байт 0x80. Это то, что вы получили бы, если бы закодировали символы в байтах с использованием UTF-8, а затем по ошибке их декодировали до символов, используя ISO-8859-1. Для этого существует специальная идиома JavaScript:
var bytelike= unescape(encodeURIComponent(characters));
и снова вернуться от псевдобайтов UTF-8 к символам:
var characters= decodeURIComponent(escape(bytelike));
(Это, в частности, в значительной степени единственный раз, когда функции escape
/unescape
должны использоваться когда-либо. Их существование в любой другой программе почти всегда является ошибкой.)
decodeURIComponent(escape(bytes))
, так как он ведет себя как декодер UTF-8, вызовет ошибку, если последовательность блоков кода, поданных в него, не будет приемлема в качестве байтов UTF-8.
Очень редко вам нужно работать с байтовыми строками, как это в JavaScript. Лучше продолжать работать в Unicode на стороне клиента. Браузер позаботится о кодировке UTF-8 строки на проводке (в форме отправки или XMLHttpRequest).
Ответ 3
Простая ошибка, большой эффект:
strTest = strTest.replace(/your regex here/g, "$1");
// ----------------------------------------^
без "глобального" флага, замена выполняется только для первого совпадения.
Примечание: Чтобы удалить любой символ, который не выполняет какое-либо сложное условие, например, попадание в набор определенных диапазонов символов Unicode, вы можете использовать отрицательный просмотр:
var re = /(?![\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})./g;
strTest = strTest.replace(re, "")
где re
читается как
(?! # 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!)
Ответ 4
Если вы пытаетесь удалить "недопустимый символ" - - из строк javascript, вы можете избавиться от них следующим образом:
myString = myString.replace(/\uFFFD/g, '')
Ответ 5
Я столкнулся с этой проблемой с действительно странным результатом данных Date Taken цифрового изображения. Мой сценарий, по общему признанию, уникален: с помощью Windows scripting host (wsh) и объекта ActiveX Shell.Application, который позволяет получить объект пространства имен в папке и вызвать функцию GetDetailsOf, чтобы по существу возвращать данные exif после того, как она была проанализирована ОС.
var app = new ActiveXObject("Shell.Application");
var info = app.Namespace("c:\");
var date = info.GetDetailsOf(info.ParseName("testimg.jpg"), 12);
В windws vista и 7 результат выглядит следующим образом:
?8/?27/?2011 ??11:45 PM
Итак, мой подход был следующим:
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];
}
Результатом курса является строка, которая исключает эти знаки вопросительного знака.
Я знаю, что вы пошли с другим решением в целом, но я думал, что опубликую свое решение, если у кого-то возникнут проблемы с этим и он не сможет использовать подход на стороне сервера.
Ответ 6
Я собрал некоторые решения, предложенные выше, чтобы избежать ошибок
var removeNonUtf8 = (characters) => {
try {
// ignore invalid char ranges
var bytelike = unescape(encodeURIComponent(characters));
characters = decodeURIComponent(escape(bytelike));
} catch (error) { }
// remove �
characters = characters.replace(/\uFFFD/g, '');
return characters;
},
Ответ 7
Я использовал решение @Ali, чтобы не только очистить мою строку, но и заменить недопустимые символы на html-замену:
cleanString(input) {
var output = "";
for (var i = 0; i < input.length; i++) {
if (input.charCodeAt(i) <= 127) {
output += input.charAt(i);
} else {
output += "&#" + input.charCodeAt(i) + ";";
}
}
return output;
}
Ответ 8
Такие языки, как испанский и французский, имеют акцентированные символы, такие как "é", а коды находятся в диапазоне 160-255 см. https://www.ascii.cl/htmlcodes.htm
function cleanString(input) {
var output = "";
for (var i=0; i<input.length; i++) {
if (input.charCodeAt(i) <= 127 || input.charCodeAt(i) >= 160 && input.charCodeAt(i) <= 255) {
output += input.charAt(i);
}
}
return output;
}