Как удалить недопустимые символы 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;
}