Как удалить недопустимые символы UTF-8 из строки JavaScript? - PullRequest
20 голосов
/ 19 апреля 2010

Я хотел бы удалить все недопустимые символы 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.

Edit: добавлен глобальный флаг к моему регулярному выражению согласно комментарию Tomalak - однако это все еще не работает для меня. Я отказываюсь делать это на стороне клиента согласно комментарию Бобинса.

Ответы [ 6 ]

24 голосов
/ 07 ноября 2013

Я использую этот простой и надежный подход:

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. Если это хороший полукок, оставьте его, если нет - бросьте его. Довольно крепкий, и если ваша цель - санитария, он достаточно быстрый (на самом деле он очень быстрый).

20 голосов
/ 19 апреля 2010

Строки 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).

8 голосов
/ 15 апреля 2016

Если вы пытаетесь удалить «недопустимый символ» - - из строк javascript, то вы можете избавиться от них следующим образом:

myString = myString.replace(/\uFFFD/g, '')
8 голосов
/ 19 апреля 2010

Простая ошибка, большой эффект:

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

без «глобального» флага, замена происходит только для первого совпадения.

Примечание: Чтобы удалить любой символ, который не выполняет какое-то сложное условие, например попадание в набор определенных диапазонов символов Юникода, вы можете использовать отрицательный прогноз:

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!)
2 голосов
/ 29 января 2012

Я столкнулся с этой проблемой с действительно странным результатом, полученным из данных Date Taken цифрового изображения. Мой сценарий, по общему признанию, уникален - с помощью хоста сценариев Windows (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]; }

Результатом, конечно же, является строка, исключающая эти знаки вопроса.

Я знаю, что вы использовали совсем другое решение, но я подумал, что опубликую свое решение на тот случай, если у кого-то возникнут проблемы с ним и он не сможет использовать языковой подход на стороне сервера.

0 голосов
/ 31 мая 2019

Я собрал некоторые решения, предложенные выше, чтобы быть безопасными для ошибок

       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;
        },
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...