Как я могу идентифицировать разные кодировки без использования спецификации?

У меня есть наблюдатель файлов, который захватывает контент из растущего файла, закодированного с помощью utf-16LE. Первый бит записанных в него данных имеет доступную спецификацию - я использовал ее, чтобы идентифицировать кодировку по UTF-8 (в которой закодировано БОЛЬШИНСТВО моих файлов). Я ловлю спецификацию и перекодирую в UTF-8, чтобы мой синтаксический анализатор не волновался. Проблема в том, что, поскольку это растущий файл, не каждый бит данных содержит спецификацию.

Вот мой вопрос - не добавляя байты спецификации к каждому набору данных, которые у меня есть (потому что у меня нет контроля над источником), могу ли я просто искать нулевые байты, которые присущи UTF- 16 \ 000, а затем использовать это как мой идентификатор вместо спецификации? Будет ли это вызывать у меня головные боли в будущем?

Моя архитектура включает в себя рубиновое веб-приложение, записывающее полученные данные во временный файл, когда мой синтаксический анализатор, написанный на 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();
  }

Что вы все думаете?


person eyberg    schedule 28.08.2009    source источник
comment
Я не понимаю, в чем проблема (вы упоминаете в первом абзаце). Конечно, не каждый фрагмент будет иметь спецификацию - но обязательно начало файла. Поэтому для каждого файла запомните, видели ли вы спецификацию, и если да, обработайте ее как UTF-16.   -  person Martin v. Löwis    schedule 28.08.2009
comment
Неужто у вас нет смешанных кодировок в одном файле?   -  person 1800 INFORMATION    schedule 28.08.2009
comment
У меня нет контроля над растущим файлом, поэтому я не могу просто перемотать файл назад. У меня нет смешанных кодировок в одном файле, но у меня есть смешанные кодировки, проходящие по сети в синтаксический анализатор, который принимает смешанные кодировки.   -  person eyberg    schedule 28.08.2009
comment
@feydr, у вас может не быть контроля над файлом, но у вас есть контроль над вашим дескриптором файла. Поиск начала вашего файла с помощью вашего дескриптора файла не повлияет ни на кого другого.   -  person paxdiablo    schedule 28.08.2009
comment
@Pax, то есть в предположении, что я ожидаю, что каждый источник будет писать в один и тот же файл - это определенно не так - отдельные биты данных попадают в очередь из многих источников - я думаю о используя `` человеческий интеллект '', зная, что определенный источник (операционная система / программа) будет создавать определенную кодировку, и используя эту информацию, чтобы определить, какую кодировку я хочу использовать ...   -  person eyberg    schedule 28.08.2009
comment
У меня нет ни контроля над файлом, ни его дескриптором - данные берутся и снимаются через HTTP - это заканчивается тем, что новый файл по-прежнему закодирован таким же образом, но иногда без спецификации   -  person eyberg    schedule 28.08.2009
comment
Тогда нет, вы не можете надежно определить кодировку, если не уверены, что символы будут ограничены подмножеством. Затем вы просто анализируете блок данных, чтобы исключить незаконное кодирование для данного подмножества. Но даже это не будет на 100% надежным.   -  person paxdiablo    schedule 28.08.2009
comment
@feydr: я считаю, что то, что вы реализовали, хрупко. Более надежным решением является захват и использование информации о кодировке символов из запросов HTTP POST.   -  person Stephen C    schedule 29.08.2009


Ответы (3)


Как правило, вы не можете определить кодировку символов потока данных со 100% точностью. Лучшее, что вы можете сделать, - это попытаться декодировать с использованием ограниченного набора ожидаемых кодировок, а затем применить некоторые эвристические методы к декодированному результату, чтобы увидеть, «похож ли он» на текст на ожидаемом языке. (Но любая эвристика даст ложные срабатывания и ложные отрицательные результаты для определенных потоков данных.) В качестве альтернативы, включите человека в цикл, чтобы решить, какое декодирование имеет наибольший смысл.

Лучшее решение - перепроектировать ваш протокол так, чтобы все, что поставляет данные, также предоставляло схему кодирования, используемую для данных. (А если вы не можете, обвините того, кто несет ответственность за разработку / внедрение системы, которая не может дать вам схему кодирования!).

РЕДАКТИРОВАТЬ: из ваших комментариев по вопросу файлы данных доставляются через HTTP. В этом случае вы должны организовать, чтобы ваш HTTP-сервер перехватывал заголовок "content-type" POST-запросов, доставляющих данные, извлекал набор символов / кодировку из заголовка и сохранял его таким образом / в том месте, которое может анализировать ваш файловый анализатор. иметь дело с.

person Stephen C    schedule 28.08.2009

Несомненно, это вызовет у вас головную боль в будущем. Вы можете проверить чередование нулевых байтов для упрощенных случаев (только ASCII, UTF-16, любой порядок байтов), но в ту минуту, когда вы начинаете получать поток символов выше кодовой точки 0x7f, этот метод становится бесполезным.

Если у вас есть дескриптор файла, лучше всего сохранить текущий указатель файла, перейти к началу, прочитать спецификацию, а затем вернуться к исходной позиции.

Либо так, либо как-нибудь запомнить спецификацию.

Полагаться на содержимое данных - это плохая идея, если вы не уверены, что диапазон символов будет ограничен для всех входных данных.

person paxdiablo    schedule 28.08.2009
comment
Полагаться на спецификацию - худшая идея, если вы не уверены, что она есть в файле. - person dan04; 15.08.2010
comment
Под вопросом был первый бит записанных данных с доступной спецификацией, поэтому я был абсолютно уверен :-) - person paxdiablo; 15.08.2010

Этот вопрос содержит несколько вариантов обнаружения символов, для которых, похоже, не требуется спецификация.

В моем проекте в настоящее время используется jCharDet, но мне, возможно, придется взглянуть на некоторые другие параметры, перечисленные там, поскольку jCharDet - это не на 100% надежен.

person jwaddell    schedule 28.08.2009
comment
@jwaddell: Никакая схема распознавания символов не будет надежной на 100%. - person Stephen C; 28.08.2009