TextDecoder.prototype.ignoreBOM 未按预期工作
TextDecoder.prototype.ignoreBOM not working as expected
我正在使用 fetch api 来提取 csv 数据并尝试创建一个 csv 文件。
但是我看到前两个字符是 ÿþ
,它们是 BOM 字符。
然而,我在解码期间设置 ignoreBOM: true
但它不起作用,我总是在 CSV
的开头看到 ÿþ
下面是我的代码
const fetchData = await newPage.evaluate(async () => {
let url = $('.csvLink').attr('href');
console.log(`in here is the ${url}`);
const stream = await fetch(url);
let reader = stream.body.getReader();
let receivedLength = 0;
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
receivedLength += value.length;
let v = new TextDecoder("ISO-8859-1", {fatal: false, ignoreBOM: false}).decode(value, {stream: true});
await window.writeToStream(v, false);
}
如果能帮助解决这个问题,那就太好了。谢谢。
ignoreBOM
only applies 用于 UTF-8 UTF-16BE 和 UTF-16LE 编码。
如果您的文件开头有一个 BOM,那么它可能没有编码为 CP-1252,而是编码为 UTF,如果该 BOM 在 CP-1252 中被读取为 ÿþ
,那么这可能是甚至是 UTF-16LE:
const littleEnd_BOM = new Uint8Array( [ 0xFF, 0xFE ] );
const as_CP1252 = new TextDecoder( 'iso-8859-1' ).decode( littleEnd_BOM );
console.log( as_CP1252 );
因此,您的代码中的第一个错误是您不想将 TextDecoder 初始化为 CP-1252,而是初始化为 UTF-16LE。
现在,对于您将 ignoreBOM
设置为哪个值存在一些混淆,在您写的某一时刻将其设置为 true
,而在代码片段中它设置为 false
(默认值)。
如果您希望 BOM 留在输出中,则将其设置为 true
。解析器将忽略该 BOM 标记,这意味着它将把它视为普通字符序列。
如果您希望它 从输出中移除 ,则将其保留为 false
,解析器将对其进行特殊处理,并将其移除从输出。
请注意,即使 BOM 在这里,它也可能不是从 DOMString 打印出来的:
const UTF16LE_text = new Uint16Array(
[ ..."\ufeffhello" ].map( (char) => char.charCodeAt(0) )
);
// to check we really wrote a LE-BOM "FFFE"
const BOM = [ ...new Uint8Array( UTF16LE_text.buffer ).slice( 0, 2 ) ]
.map( (v) => v.toString( 16 ) ).join('');
console.log( 'BOM:', BOM );
const ignoring_decoder = new TextDecoder( 'UTF-16LE', { ignoreBOM: true } );
const ignored = ignoring_decoder.decode( UTF16LE_text );
console.log( 'ignoreBOM:true - text:', ignored );
console.log( 'ignoreBOM:true - char at 0:', ignored.charCodeAt( 0 ) );
const removing_decoder = new TextDecoder( 'UTF-16LE' );
const removed = removing_decoder.decode( UTF16LE_text );
console.log( 'ignoreBOM:false - text:', removed );
console.log( 'ignoreBOM:false - char at 0:', removed.charCodeAt( 0 ) );
但您可能面临的另一个问题是,您正在读取获取的文本块,即随机大小的数据块。
文本不能以这种方式处理,您需要从明确定义的字节位置解析它才能正确解析它。
幸运的是,TextDecoder.decode()
方法有一个 stream
选项。使用它,解码器应该能够正确读取流,但要使此选项起作用,您需要将 TextDecoder 存储在 while 循环之外,以便它可以将之前的缓冲区保留在内存中。
const fetchData = await newPage.evaluate(async () => {
let url = $('.csvLink').attr('href');
const stream = await fetch(url);
let reader = stream.body.getReader();
let receivedLength = 0;
// declare the decoder outside of the loop
const decoder = new TextDecoder("UTF-16LE");
while(true) {
const {done, value} = await reader.read();
receivedLength += value.length;
// always use the same decoder
const v = decoder.decode(value, {stream: true});
await window.writeToStream(v, false);
if (done) {
break;
}
}
}
我正在使用 fetch api 来提取 csv 数据并尝试创建一个 csv 文件。
但是我看到前两个字符是 ÿþ
,它们是 BOM 字符。
然而,我在解码期间设置 ignoreBOM: true
但它不起作用,我总是在 CSV
ÿþ
下面是我的代码
const fetchData = await newPage.evaluate(async () => {
let url = $('.csvLink').attr('href');
console.log(`in here is the ${url}`);
const stream = await fetch(url);
let reader = stream.body.getReader();
let receivedLength = 0;
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
receivedLength += value.length;
let v = new TextDecoder("ISO-8859-1", {fatal: false, ignoreBOM: false}).decode(value, {stream: true});
await window.writeToStream(v, false);
}
如果能帮助解决这个问题,那就太好了。谢谢。
ignoreBOM
only applies 用于 UTF-8 UTF-16BE 和 UTF-16LE 编码。
如果您的文件开头有一个 BOM,那么它可能没有编码为 CP-1252,而是编码为 UTF,如果该 BOM 在 CP-1252 中被读取为 ÿþ
,那么这可能是甚至是 UTF-16LE:
const littleEnd_BOM = new Uint8Array( [ 0xFF, 0xFE ] );
const as_CP1252 = new TextDecoder( 'iso-8859-1' ).decode( littleEnd_BOM );
console.log( as_CP1252 );
因此,您的代码中的第一个错误是您不想将 TextDecoder 初始化为 CP-1252,而是初始化为 UTF-16LE。
现在,对于您将 ignoreBOM
设置为哪个值存在一些混淆,在您写的某一时刻将其设置为 true
,而在代码片段中它设置为 false
(默认值)。
如果您希望 BOM 留在输出中,则将其设置为 true
。解析器将忽略该 BOM 标记,这意味着它将把它视为普通字符序列。
如果您希望它 从输出中移除 ,则将其保留为 false
,解析器将对其进行特殊处理,并将其移除从输出。
请注意,即使 BOM 在这里,它也可能不是从 DOMString 打印出来的:
const UTF16LE_text = new Uint16Array(
[ ..."\ufeffhello" ].map( (char) => char.charCodeAt(0) )
);
// to check we really wrote a LE-BOM "FFFE"
const BOM = [ ...new Uint8Array( UTF16LE_text.buffer ).slice( 0, 2 ) ]
.map( (v) => v.toString( 16 ) ).join('');
console.log( 'BOM:', BOM );
const ignoring_decoder = new TextDecoder( 'UTF-16LE', { ignoreBOM: true } );
const ignored = ignoring_decoder.decode( UTF16LE_text );
console.log( 'ignoreBOM:true - text:', ignored );
console.log( 'ignoreBOM:true - char at 0:', ignored.charCodeAt( 0 ) );
const removing_decoder = new TextDecoder( 'UTF-16LE' );
const removed = removing_decoder.decode( UTF16LE_text );
console.log( 'ignoreBOM:false - text:', removed );
console.log( 'ignoreBOM:false - char at 0:', removed.charCodeAt( 0 ) );
但您可能面临的另一个问题是,您正在读取获取的文本块,即随机大小的数据块。
文本不能以这种方式处理,您需要从明确定义的字节位置解析它才能正确解析它。
幸运的是,TextDecoder.decode()
方法有一个 stream
选项。使用它,解码器应该能够正确读取流,但要使此选项起作用,您需要将 TextDecoder 存储在 while 循环之外,以便它可以将之前的缓冲区保留在内存中。
const fetchData = await newPage.evaluate(async () => {
let url = $('.csvLink').attr('href');
const stream = await fetch(url);
let reader = stream.body.getReader();
let receivedLength = 0;
// declare the decoder outside of the loop
const decoder = new TextDecoder("UTF-16LE");
while(true) {
const {done, value} = await reader.read();
receivedLength += value.length;
// always use the same decoder
const v = decoder.decode(value, {stream: true});
await window.writeToStream(v, false);
if (done) {
break;
}
}
}