Javascript 在类型化数组中查找字节序列,而无需编写Boyer-Moore实现

Javascript 在类型化数组中查找字节序列,而无需编写Boyer-Moore实现,javascript,fileapi,arraybuffer,typed-arrays,Javascript,Fileapi,Arraybuffer,Typed Arrays,我必须在用户加载的文件中找到一些标记(文本序列)。这些文件中有85%是UTF-8编码的文本,但也会有二进制文件。标记现在是文本序列,但将来可能会使用正则表达式(可能不会用于二进制文件,但我还不知道) 我的文件内容是ArrayBufferarrays,我必须在该数据中找到标记。我有以下选择: 使用类型化数组(UInt8Array)和textdecker('ascii'),并对解码数据使用String.indexOf()。我不喜欢这样,因为至少在原则上,这可以复制textdecker.decode(

我必须在用户加载的文件中找到一些标记(文本序列)。这些文件中有85%是UTF-8编码的文本,但也会有二进制文件。标记现在是文本序列,但将来可能会使用正则表达式(可能不会用于二进制文件,但我还不知道)

我的文件内容是
ArrayBuffer
arrays,我必须在该数据中找到标记。我有以下选择:

  • 使用类型化数组(
    UInt8Array
    )和
    textdecker('ascii')
    ,并对解码数据使用
    String.indexOf()
    。我不喜欢这样,因为至少在原则上,这可以复制
    textdecker.decode()之后文件内容使用的内存。但这很简单,也很简单。也适用于二进制文件,因为标记将是二进制数据中的ASCII字节
  • 再次使用键入的数组(
    UInt8Array
    ),编写自己版本的Boyer Moore或其他快速字符串搜索函数,以查找所需的字节序列。快速,内存优化。。。但我不想再写一个Boyer Moore实现或复制一个。记住,将来我可能会使用正则表达式,所以
  • 将文件作为文本而不是
    ArrayBuffer
    ,因为它们中有85%是UTF-8编码的文本,并尝试使用我将遇到的几个真正的二进制文件做一些特别的事情。这意味着我可以从一开始就使用正则表达式或
    String.indexOf()
    ,这没什么大不了的,但另一方面,在找到标记后处理二进制文件可能是个问题,因为原始数据将转换为文本
  • 由于将来几乎可以保证使用正则表达式,我唯一的清晰路径是第一条,但我非常担心内存使用,因为有些文件可能很大(大约100 MB左右),或者使用第三个选项,看看如何在转换为文本后获取原始字节

    有什么建议吗?我错过了什么明显的东西吗


    提前谢谢

    您可以将数组缓冲区解码为文本流。
    有一个,但FF中仍然不支持它,它需要在Blob中复制ArrayBuffers,以便对其进行流式传输

    因此,在使用ArrayBuffers的情况下,您可以使用该方法的
    stream
    选项,并按小块读取ArrayBuffer:

    const buffer_1=new textcoder().encode(“AAABCBAB”).buffer;
    //预期指数:[2,6]^^
    常量索引_1=获取索引(缓冲区_1,“AB”,每次3/*3字节*/);
    log(“缓冲区1”,
    JSON.stringify(索引_1),
    //检查他们是否都是“AB”
    stringify(提取内容(缓冲区1,索引1,2))
    );
    //更复杂的测试,使用随机二进制数据(读作UTF-8)
    常量缓冲区_2=uint32数组自(
    {长度:1024*1024},
    ()=>Math.random()*0xFFFFFFFF
    ).缓冲器;
    常量索引_2=获取索引(缓冲区_2,“AB”);
    log(“缓冲区2”,
    JSON.stringify(索引_2),
    //检查他们是否都是“AB”
    stringify(提取内容(缓冲区2,索引2,2))
    );
    函数getAllIndices(缓冲区、标记、chunksize=1024/*字节*/){
    如果(!marker){return null;}
    if(!(RegExp的标记实例)){
    marker=新的RegExp(marker,“g”);
    }
    marker.global=true;
    //标记可以分为两块。
    //因此,在每一块中,我们都会预加最后几个字符
    //最后一块。
    常量标记长度=marker.source.length;
    常量位置=[];
    const arr=新的Uint8Array(缓冲区);
    const decoder=新文本解码器();
    设当前_指数=0;
    设全长=0;
    让标记_buffer=“”;
    while(当前_指数-1?
    (最后索引+标记长度):
    (解码长度-标记长度);
    marker\u buffer=解码的.slice(marker\u索引);
    }
    返回位置;
    }
    //仅供演示
    函数提取内容(缓冲区、索引、长度){
    const full_str=新文本解码器()。解码(缓冲区);
    返回index.map((index)=>full_str.slice(index,index+length));
    
    }
    是的,我知道,我可能在这里工作过度,可能
    textdecker
    不会像我想的那样消耗内存。事实上,我所做的测试表明了这一点。但无论如何,我想在这里看到更多的选择,只是为了确保我没有遗漏一些明显的东西…Kaido,这是你今天第二次帮助我,非常感谢你提供的信息和代码。我知道TextDecoderStream,但是代码必须在FF中工作,所以我拒绝了它,并且我不知道stream选项。我已经读了很多次说明书,以至于我对这些信息视而不见。我想我可以修改代码,这样我将处理的标记就不会太麻烦了,希望如此。由于标记在最初的几个kb中,比如90%的时间,我可以使用stream选项并为边缘情况定制一些解决方案。非常感谢,真的。