Как записывать ошибки декодирования utf-8 в node.js?

Я только что обнаружил, что Node (проверено: v0.8.23, текущий git: v0.11.3-pre) игнорирует любые ошибки декодирования в обработке буфера, молча заменяя любые символы не-utf8 '\ufffd' (Unicode REPLACEMENT CHARACTER) вместо того, чтобы бросать исключение из ввода non-utf8. Как следствие, fs.readFile, process.stdin.setEncoding и друзья маскируют для вас большой класс ошибок ввода.

Пример, который не терпит неудачу, но действительно должен:

> notValidUTF8 = new Buffer([ 128 ], 'binary')
<Buffer 80>
> decodedAsUTF8 = notValidUTF8.toString('utf8') // no exception thrown here!
'�'
> decodedAsUTF8 === '\ufffd'
true

'\ufffd' является вполне допустимым символом, который может иметь место в юридическом utf8 (как последовательность ef bf bd), поэтому нетривиально для monkey-patch при обработке ошибок на основе этого, появляющегося в результате.

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

Существуют ли Node модули или что-то другое, что позволяет мне поймать ошибки декодирования utf-8, предпочтительнее с контекстом о том, где ошибка была обнаружена во входной строке или буфере?

Ответ 1

Надеюсь, вы решили проблему в те годы, у меня был подобный и в конце концов решил с этим уродливым трюком:

  function isValidUTF8(buf){
   return Buffer.compare(new Buffer(buf.toString(),'utf8') , buf) === 0;
  }

который преобразует буфер назад и вперед и проверяет, остается ли он.

Кодирование 'utf8' может быть опущено.

Тогда имеем:

> isValidUTF8(new Buffer('this is valid, 指事字 eè we hope','utf8'))
true
> isValidUTF8(new Buffer([128]))
false
> isValidUTF8(new Buffer('\ufffd'))
true

где символ '\ ufffd' корректно считается действительным utf8.

UPDATE: теперь это работает и в JXcore.

Ответ 2

Как сказал Джош К., выше: "npmjs.org/package/encoding"

На веб-сайте npm: "кодирование - это простая оболочка вокруг node -iconv и iconv-lite для преобразования строк из одной кодировки в другую.

Скачать: $ npm install encoding

Пример использования

var result = encoding.convert(new Buffer([ 128 ], 'binary'), "utf8");
console.log(result); //<Buffer 80>

Посетите сайт: npm - encoding

Ответ 3

Начиная с узла 8.3, вы можете использовать util.TextDecoder для решения этой проблемы:

const util = require('util')
const td = new util.TextDecoder('utf8', {fatal:true})
td.decode(Buffer.from('foo')) // works!
td.decode(Buffer.from([ 128 ], 'binary')) // throws TypeError

Это также будет работать в некоторых браузерах с использованием TextDecoder в глобальном пространстве имен.