首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >检测'text‘文件类型(ANSI vs UTF-8)

检测'text‘文件类型(ANSI vs UTF-8)
EN

Stack Overflow用户
提问于 2011-02-06 00:11:08
回答 6查看 28.7K关注 0票数 11

我用Delphi (7)写了一个应用程序(心理测试测试),它创建了一个标准的文本文件--即该文件是ANSI类型的。

有人将该程序移植到Internet上运行,可能是使用Java,生成的文本文件是UTF-8类型。

读取这些结果文件的程序必须读取由Delphi创建的文件和通过Internet创建的文件。

虽然我可以将UTF-8文本转换为ANSI (使用巧妙命名的函数UTF8ToANSI),但我如何提前知道我有哪种文件?

考虑到我“拥有”文件格式,我想处理这个问题的最简单方法是在文件中的已知位置放置一个标记,它将告诉我程序的来源(Delphi/Internet),但这似乎是作弊。

提前谢谢。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-02-06 00:15:24

如果UTF文件以UTF-8字节顺序标记(BOM)开头,这很容易:

代码语言:javascript
复制
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;

否则,就会困难得多。

票数 2
EN

Stack Overflow用户

发布于 2011-02-06 00:28:17

没有100%确定的方法来识别ANSI (例如Windows-1250)编码和UTF-8编码。有些ANSI文件不能是有效的UTF-8,但每个有效的UTF-8文件都可能是不同的ANSI文件。(更不用说定义为ANSI和UTF-8的纯ASCII数据,但这纯粹是一个理论方面。)

例如,序列C4 8D在UTF-8中可能是“č”字符,在windows-1250中可能是“Ť”。这两种方法都是可能的,而且都是正确的。然而,例如8D 9A可以是windows-1250中的“Ťš”,但它不是有效的UTF-8字符串。

你必须求助于某种启发式方法,例如:

如果文件包含的序列不能是有效的UTF-8,则假定它是ANSI.

  • Otherwise,如果文件以UTF-8 BOM (EF BB BF)开头,则假定它是UTF-8 (它可能不是,但是,以这样的字符开头的纯文本
  1. 文件非常improbable).
  2. Otherwise,假设它是UTF-8。(或者,尝试更多的启发式方法,也许使用文本语言的知识,等等)

另请参见the method used by Notepad

票数 21
EN

Stack Overflow用户

发布于 2011-02-25 17:34:05

如果我们对求和,那么:

  • 使用basic的最佳解决方案是使用过时的(如果我们使用IsTextUnicode(););
  • 使用高级的最佳解决方案是使用上面的函数,然后检查物料清单(~ 1KB ),然后检查特定操作系统下的区域设置信息,然后才能获得约98%的准确率?<代码>H211<代码>F212

人们可能会感兴趣的其他信息:

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

代码语言:javascript
复制
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;

现在测试这个函数...

在我看来,如何正确地开始检查的唯一方法是首先检查操作系统字符集,因为在最后,几乎所有的情况下都会引用一些操作系统。不管怎么说都没办法让它消失。

备注:

  • WideFileExists()函数取自TntClasses.pas ( Koders.net source )。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4907942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档