检测'文本'文件类型(ANSI与UTF-8)

No'*_*man 8 delphi utf-8 delphi-7

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

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

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

虽然我可以将UTF-8文本转换为ANSI(使用狡猾命名的函数UTF8ToANSI),但我怎么能提前告诉我有哪种文件?

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

提前致谢.

Mor*_*gil 18

没有100%可靠的方法来识别UTF-8编码的ANSI(例如Windows-1250)编码.这里其中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 BOM(EF BB BF)开头,则假设它是UTF-8(但可能不是,但是,以这些字符开头的纯文本ANSI文件非常不可能).
  3. 否则,假设它是UTF-8.(或者,尝试更多启发式,也许使用文本语言的知识等)

另请参阅记事本使用的方法.


And*_*and 2

如果 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;
Run Code Online (Sandbox Code Playgroud)

否则,难度就大得多。

  • 在 UTF-8 数据上查找 BOM 的情况非常罕见,因为 UTF-8 与字节顺序无关,因此[不需要 BOM 来确定字节顺序](http://unicode.org/faq/utf_bom.html#utf8 -2)。 (13认同)
  • @Andreas我是两个投反对票的人之一,我想我解释了原因。90+% 的情况下,您的答案根本没有帮助,因为 UTF-8 文件很少有 BOM。这有点像回答“如何在 Java 中复制 MySQL 的‘utf8_unicode_ci’?” 说“好吧,如果两个字符串都为空,则返回 0。否则,会困难得多。” 是的,这是真的。但没有帮助。 (6认同)
  • @Andreas哦,是的。但这个答案仍然是-1。您“真的”不能指望 UTF-8 数据中包含 BOM。一个*好的*答案会尝试测试数据是否有效 UTF-8... (4认同)
  • @dkarp ANSI 这个词作为 Microsoft 意味着本地遗留字符集,并且根据操作系统语言的不同,系统之间可能有所不同。 (4认同)
  • @David:这个答案基本上是说“寻找 BOM”。(这就是代码所做的全部工作。)不过,十有八九,UTF-8 文件没有 BOM,因为它“不需要”BOM... (3认同)
  • 我接受这个答案,因为该程序的 Internet 版本创建的文件确实有 BOM - 它的前三个字符是 EF BB BF。我将要求创建互联网版本的人创建更多文件,以便我可以更彻底地检查这一点。感谢所有参与了的人。 (2认同)
  • +1,正如安德烈亚斯所说,答案是正确的并且条件已陈述。根本没有理由反对它! (2认同)