Конференция "Прочее" » определить UTF8 без BOM
 
  • kashey © (16.08.18 12:41) [0]
    Нагуглил вариант:

    Если количество символов #$D0, #$D1 превышает треть от количества остальных символов с кодами >127, то это с очень высокой вероятностью UTF-8.


    Но правильно срабатывает не всегда. Понятно что 100% алгоритма нет, но хотелось бы что-то понадежней, тот-же Notepad++ чтобы ошибался в кодировке, пока не наблюдал.
    Наверняка есть варианты получше моего. Просвятите пожалуйста кто знает.
  • Inovet © (16.08.18 12:47) [1]
    Надо искать или самому сгенерировать таблицы частоты встречаемости символов для разных кодировок, типов текстов и языков.
  • kashey © (16.08.18 12:58) [2]
    Этот вариант нагуглили на DelphiKingdom::ответ Python

    Первый вариант. Если количество символов #$D0, #$D1 превышает треть от количества остальных символов с кодами >127, то это с очень высокой вероятностью UTF-8.

    Второй вариант - пытаться декодировать файл в кодировке UTF-8, если символов с кодами >127 не найдено - это точно не UTF-8, а если ошибок не было - то точно UTF-8 (если есть ошибки - принимать решение, 1-2 ошибки на десятки тысяч символов - это можно игнорировать).


    Я вообще не въехал как реализовать второй вариант, ну хотя бы >>пытаться декодировать файл в кодировке UTF-8. Если я заведомо не могу знать в какой он кодировке.
  • Inovet © (16.08.18 13:23) [3]
    > [2] kashey ©   (16.08.18 12:58)

    Ключевое слово - пытаться.
  • RWolf © (16.08.18 14:18) [4]
    Байты $80 и выше в текстовом файле UTF-8 подчиняются определённым правилам, см. алгоритм кодирования символов в UTF-8. Соответственно, если в файле такие байты есть, но правила не соблюдаются, это наверняка не UTF-8.
  • Styx © (16.08.18 15:18) [5]

    > тот-же Notepad++ чтобы ошибался в кодировке, пока не наблюдал.

    Дык смотрите исходники: https://github.com/notepad-plus-plus/notepad-plus-plus
  • kashey © (16.08.18 15:27) [6]

    > Второй вариант - пытаться декодировать файл в кодировке
    > UTF-8, если символов с кодами >127 не найдено - это точно
    > не UTF-8, а если ошибок не было - то точно UTF-8 (если есть
    > ошибки - принимать решение, 1-2 ошибки на десятки тысяч
    > символов - это можно игнорировать).
    >


    Пытался выразить это в коде, но видать не то:

       err_count := 0;
       sumb127 := 0;
       for i := 0 to FStringList.Count - 1 do begin
         try
           bufs := UTF8Decode(FStringList[i]);
           for j := 1 to Length(bufs) do begin
             if Ord(bufs[j]) > 127 then Inc(sumb127);
           end;
         except
           Inc(err_count);
         end;
       end;

       if sumb127 = 0 then begin
         ShowMessage('Точно не UTF-8');
       end
       else if err_count = 0 then begin
         ShowMessage('Точно UTF-8');
       end
       else if (Length(FStringList.Text) / err_count) > 2000 then begin
         ShowMessage('Скорее всего UTF-8');
       end
       else begin
         ShowMessage('Другая кодировка');
       end;
  • kashey © (16.08.18 15:29) [7]

    > Дык смотрите исходники: https://github.com/notepad-plus-
    > plus/notepad-plus-plus

    В этом ворохе файлов попробуй найди то что надо.
  • kashey © (16.08.18 15:48) [8]
    А кажись нашел, но как эту жуткую кракозябру перевести на нормальный язык


    namespace Utf8 { // could be a static class, instead of a namespace, if it needs private members
    // basic classification of UTF-8 bytes
    inline static bool isSingleByte(UCHAR c)       { return c < 0x80; }

    inline static bool isPartOfMultibyte(UCHAR c)  { return c >= 0x80; }
    inline static bool isFirstOfMultibyte(UCHAR c) { return c >= 0xC2 && c < 0xF5; } // 0xF5 to 0xFD are defined by UTF-8, but are not currently valid Unicode
    inline static bool isContinuation(UCHAR c)     { return (c & 0xC0) == 0x80; }
    inline static bool isValid(UCHAR c)            { return c < 0xC0 || isFirstOfMultibyte(c); } // validates a byte, out of context

    // number of continuation bytes for a given valid first character (0 for single byte characters)
    inline static int  continuationBytes(UCHAR c)  {
     static const char _len[] = { 1,1,2,3 }
    ;
     return (c < 0xC0) ? 0 : _len[(c & 0x30) >>  4];
    }

    // validates a full character
    inline static bool isValid(const char* buf, int buflen) {
     if(isSingleByte(buf[0])) return true; // single byte is valid
     if(!isFirstOfMultibyte(buf[0])) return false; // not single byte, nor valid multi-byte first byte
     int charContinuationBytes = continuationBytes(buf[0]);
     if(buflen < charContinuationBytes+1) return false; // character does not fit in buffer
     for(int i = charContinuationBytes; i>0; --i)
      if(!isContinuation(*(++buf))) return false; // not enough continuation bytes
     return true;  // the character is valid (if there are too many continuation bytes, it is the next character that will be invalid)
    }


    // rewinds to the first byte of a multi-byte character for any valid UTF-8 (and will not rewind too much on any other input)
    inline static int characterStart(const char* buf, int startingIndex) {
     int charContinuationBytes = 0;
     while(charContinuationBytes < startingIndex // rewind past start of buffer?
      && charContinuationBytes < 5 // UTF-8 support up to 5 continuation bytes (but valid sequences currently do not have more than 3)
      && isContinuation(buf[startingIndex-charContinuationBytes])
      )
      ++charContinuationBytes;
     return startingIndex-charContinuationBytes;
    }

    };

  • Styx © (16.08.18 16:01) [9]

    > В этом ворохе файлов попробуй найди то что надо.

    Где-то здесь: https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/uchardet/README.TXT

    Uchardet is a C language binding of the original C++ implementation of the universal charset detection library by Mozilla.
    The source code of universalchardet is available at https://github.com/BYVoid/uchardet

    Текущая версия библиотеки здесь: https://www.freedesktop.org/wiki/Software/uchardet/
  • DayGaykin © (16.08.18 17:32) [10]

    > если символов с кодами >127 не найдено - это точно не UTF-
    > 8

    Еще какой UTF8.

    Однозначно не определишь.
  • kashey © (16.08.18 17:42) [11]
    Кучу готовый примеров на Си нагуглил и не одного Delphi. Плохо искал? Попытаюся переписать с Си.
  • Styx © (16.08.18 18:07) [12]
    Плохо. Вот, нашёлся за 2 секунды: https://sourceforge.net/projects/chsdet/files/chsdet/0.2/chsdet_026_src.zip/download
    Что внутри - не смотрел :)
  • kashey © (16.08.18 18:13) [13]

    > Что внутри - не смотрел :)

    Ну да может вирусяка )
  • Styx © (16.08.18 18:20) [14]
    Это исходники жеж :)
  • aka © (16.08.18 19:50) [15]
 
Конференция "Прочее" » определить UTF8 без BOM
Есть новые Нет новых   [118679   +72][b:0][p:0.002]