java - 如何在不使用 BOM 的情况下识别不同的编码?

标签 java utf-8 utf-16 byte-order-mark

我有一个文件观察器,它正在从使用 utf-16LE 编码的不断增长的文件中获取内容。写入其中的第一位数据具有可用的 BOM——我使用它来识别针对 UTF-8 的编码(我传入的大部分文件都是用该编码进行编码的)。我捕获 BOM 并重新编码为 UTF-8,这样我的解析器就不会崩溃。问题是,由于它是一个不断增长的文件,因此并非每一位数据都包含 BOM。

这是我的问题 - 如果不将 BOM 字节添加到我拥有的每组数据中(因为我无法控制源),我可以只查找固有的空字节吗UTF-16\000,然后使用它作为我的标识符而不是 BOM?这会让我以后头疼吗?

我的架构涉及一个 ruby​​ Web 应用程序,当我用 java 编写的解析器接收到接收到的数据时,将其记录到临时文件中。

现在写我的识别/重新编码代码如下所示:

  // guess encoding if utf-16 then
  // convert to UTF-8 first
  try {
    FileInputStream fis = new FileInputStream(args[args.length-1]);
    byte[] contents = new byte[fis.available()];
    fis.read(contents, 0, contents.length);

    if ( (contents[0] == (byte)0xFF) && (contents[1] == (byte)0xFE) ) {
      String asString = new String(contents, "UTF-16");
      byte[] newBytes = asString.getBytes("UTF8");
      FileOutputStream fos = new FileOutputStream(args[args.length-1]);
      fos.write(newBytes);
      fos.close();
    }

    fis.close();
    } catch(Exception e) {
      e.printStackTrace();
  }

更新

我想支持欧元、破折号和其他字符等内容。 我将上面的代码修改为如下所示,它似乎通过了我所有的测试 对于这些字符:

  // guess encoding if utf-16 then
  // convert to UTF-8 first
  try {
    FileInputStream fis = new FileInputStream(args[args.length-1]);
    byte[] contents = new byte[fis.available()];
    fis.read(contents, 0, contents.length);
    byte[] real = null;

    int found = 0;

    // if found a BOM then skip out of here... we just need to convert it
    if ( (contents[0] == (byte)0xFF) && (contents[1] == (byte)0xFE) ) {
      found = 3;
      real = contents;

    // no BOM detected but still could be UTF-16
    } else {

      for(int cnt=0; cnt<10; cnt++) {
        if(contents[cnt] == (byte)0x00) { found++; };

        real = new byte[contents.length+2];
        real[0] = (byte)0xFF;
        real[1] = (byte)0xFE;

        // tack on BOM and copy over new array
        for(int ib=2; ib < real.length; ib++) {
          real[ib] = contents[ib-2];
        }
      }

    }

    if(found >= 2) {
      String asString = new String(real, "UTF-16");
      byte[] newBytes = asString.getBytes("UTF8");
      FileOutputStream fos = new FileOutputStream(args[args.length-1]);
      fos.write(newBytes);
      fos.close();
    }

    fis.close();
    } catch(Exception e) {
      e.printStackTrace();
  }

大家觉得怎么样?

最佳答案

一般来说,你无法100%准确地识别数据流的字符编码。您能做的最好的事情就是尝试使用一组有限的预期编码进行解码,然后对解码结果应用一些启发式方法,看看它是否“看起来像”预期语言中的文本。 (但是任何启发式方法都会对某些数据流给出误报和漏报。)或者,让人工参与循环来决定哪种解码最有意义。

更好的解决方案是重新设计协议(protocol),以便提供数据的任何内容也必须提供用于数据的编码方案。 (如果你不能,请责怪负责设计/实现无法为你提供编码方案的系统的人!)。

编辑:根据您对问题的评论,数据文件是通过 HTTP 传递的。在这种情况下,您应该安排您的 HTTP 服务器捕获传递数据的 POST 请求的“内容类型” header ,从 header 中提取字符集/编码,并将其保存在文件解析器可以使用的方式/位置处理。

关于java - 如何在不使用 BOM 的情况下识别不同的编码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1344452/

相关文章:

java - 看来 retransformClasses 删除了用户定义的属性(?)如何向通过重新转换保留的方法添加注释?

c++ - 如何将 UTF-16 中的字符串转换为 C++ 中的 UTF-8

java - 使用 java 在 Mac 上设置与 Oracle 的连接

java - 如何连接到eureka中的应用程序实例?

java - 想法不显示子项目

r - 将语言环境设置为系统默认 UTF-8

java - 为什么 JSOUP 不能读取为 UTF-8?

c++ - 为什么 `wstring_convert` 抛出 range_error?

java - Character可以代表所有的unicode码位吗?

c# - UTF-16 是 ASCII 的超集吗?如果是,为什么根据 HTML 标准 UTF-16 与 ASCII 不兼容?