Как записывать ошибки декодирования 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
в глобальном пространстве имен.