Определение типа текстового файла (ANSI против UTF-8) - PullRequest
7 голосов
/ 05 февраля 2011

Я написал приложение (экзамен на психологическое тестирование) в Delphi (7), в котором создается стандартный текстовый файл, т. Е. Файл типа ANSI.

Кто-то перенес программу для запуска в Интернете, возможно, с использованием Java, и полученный текстовый файл имеет тип UTF-8.

Программа, которая читает эти файлы результатов, должна будет читать как файлы, созданные Delphi, так и файлы, созданные через Интернет.

Хотя я могу преобразовать текст UTF-8 в ANSI (используя хитро названную функцию UTF8ToANSI), как я могу заранее сказать, какой тип файла у меня есть?

Видя, как я владею«Формат файла, я полагаю, что самый простой способ справиться с этим - разместить маркер внутри файла в известной позиции, которая сообщит мне об источнике программы (Delphi / Internet), но, похоже, это обман.

Заранее спасибо.

Ответы [ 4 ]

18 голосов
/ 05 февраля 2011

Нет 100% надежного способа распознавания кодировки ANSI (например, Windows-1250) из кодировки UTF-8. - это файлы ANSI, которые не могут быть действительным UTF-8, но каждый действительный файл UTF-8 также может быть другим файлом ANSI.(Не говоря уже о ASCII-данных, которые по определению являются и ANSI и UTF-8, но это чисто теоретический аспект.)

Например, последовательность C4 8D может бытьсимвол «č» в UTF-8, или это может быть «ÄŤ» в windows-1250.И то, и другое возможно и правильно.Однако, например, 8D 9A может быть «Ťš» в Windows-1250, но это не допустимая строка UTF-8.

Вы должны прибегнуть к некоторой эвристике, например

  1. Если файл содержит последовательность, которая не может быть действительным UTF-8, предположим, что это ANSI.
  2. В противном случае, если файл начинается с спецификации UTF-8 (EF BB BF), предположим, что это UTF-8 (однако это не может быть простой текстовый файл ANSI, начинающийся с таких символов, очень маловероятно).
  3. В противном случае предположим, что это UTF-8.(Или попробуйте больше эвристики, возможно, используя знание языка текста и т. Д.)

См. Также метод, используемый Notepad .

1 голос
/ 25 февраля 2011

Если мы суммируем , то:

  • Лучшее решение для базового использования - использование устаревшего (если мы используем IsTextUnicode () ;);
  • Лучшее решение для использования продвинутый - использовать вышеуказанную функцию, затем проверить BOM (~ 1 КБ), затем проверитьИнформация о локали в конкретной ОС и только тогда вы получите 98% точность?

ДРУГАЯ ИНФОРМАЦИЯ ЛЮДИ МОГУТ НАЙТИ ИНТЕРЕСНЫЕ:

https://groups.google.com/forum/?lnk=st&q=delphi+WIN32+functions+to+detect+which+encoding++is+in+use&rnum=1&hl=pt-BR&pli=1#!topic/borland.public.delphi.internationalization.win32/_LgLolX25OA

function FileMayBeUTF8(FileName: WideString): Boolean;
var
 Stream: TMemoryStream;
 BytesRead: integer;
 ArrayBuff: array[0..127] of byte;
 PreviousByte: byte;
 i: integer;
 YesSequences, NoSequences: integer;

begin
   if not WideFileExists(FileName) then
     Exit;
   YesSequences := 0;
   NoSequences := 0;
   Stream := TMemoryStream.Create;
   try
     Stream.LoadFromFile(FileName);
     repeat

     {read from the TMemoryStream}

       BytesRead := Stream.Read(ArrayBuff, High(ArrayBuff) + 1);
           {Do the work on the bytes in the buffer}
       if BytesRead > 1 then
         begin
           for i := 1 to BytesRead-1 do
             begin
               PreviousByte := ArrayBuff[i-1];
               if ((ArrayBuff[i] and $c0) = $80) then
                 begin
                   if ((PreviousByte and $c0) = $c0) then
                     begin
                       inc(YesSequences)
                     end
                   else
                     begin
                       if ((PreviousByte and $80) = $0) then
                         inc(NoSequences);
                     end;
                 end;
             end;
         end;
     until (BytesRead < (High(ArrayBuff) + 1));
//Below, >= makes ASCII files = UTF-8, which is no problem.
//Simple > would catch only UTF-8;
     Result := (YesSequences >= NoSequences);

   finally
     Stream.Free;
   end;
end;

Теперь тестируем эту функцию ...

По моему скромному мнению, единственный способ, как НАЧАТЬ сделать эту проверку правильно, это проверить кодировку ОС в первую очередь, потому что в конце концов почти во всех случаях сделаны некоторыессылки на ОС.В любом случае, не существует способа ...

Замечания:

1 голос
/ 05 февраля 2011

Если файл UTF начинается с метки порядка байтов UTF-8 (BOM), это легко:

function UTF8FileBOM(const FileName: string): boolean;
var
  txt: file;
  bytes: array[0..2] of byte;
  amt: integer;
begin

  FileMode := fmOpenRead;
  AssignFile(txt, FileName);
  Reset(txt, 1);

  try
    BlockRead(txt, bytes, 3, amt);
    result := (amt=3) and (bytes[0] = $EF) and (bytes[1] = $BB) and (bytes[2] = $BF);
  finally    
    CloseFile(txt);
  end;

end;

В противном случае это намного сложнее.

0 голосов
/ 05 февраля 2011

При чтении сначала попробуйте проанализировать файл как UTF-8.Если он недействителен, UTF-8 интерпретирует файл как устаревшую кодировку (ANSI).Это будет работать с большинством файлов, так как очень маловероятно, что унаследованный кодированный файл будет действительным UTF-8.

То, что Windows называет ANSI, является кодировкой, зависящей от локали системы.И текст не будет работать правильно на русском, азиатском или ... windows.

Хотя VCL не поддерживает Unicode в Delphi 7, вы все равно должны внутренне работать с Unicode и конвертировать только в ANSIдля отображения.Я локализовал одну из своих программ на корейский и русский языки, и это был единственный способ заставить ее работать без больших проблем.Вы по-прежнему можете отображать корейскую локализацию только в системе, настроенной на корейский, но по крайней мере текстовые файлы можно редактировать в любой системе.

...