TStringList对非ANSI文件的处理方式

5
在我的应用程序中,当我想要导入一个文件时,我使用TStringList。但是,当有人从Excel中导出数据时,文件编码为UCS-2小端,TStringList无法读取数据。是否有任何方法来验证此情况,识别文本编码并向用户发送警告,说明提供的文本不兼容?仅为明确起见,用户将只提供纯文本..字母和数字,否则,我必须发送警告。Unicode文件(不带BOM)很好。(TStringList可以读取它!)ANSI文件也可以。(TStringList可以读取它!)即使是带BOM的Unicode文件也可以,如果有一种方法可以删除它。(TStringList可以读取它!但会出现“i”、“>>”和“reverse?”字符,这些属于BOM字节)

@DavidHeffernan 是的,Delphi 6 - EProgrammerNotFound
Jedi Code Library有支持Unicode的字符串列表可供使用。 - Arioch 'The
1个回答

8
我在 Delphi 6 中使用了下面这个函数来检测 Unicode BOM 。
const
  //standard byte order marks (BOMs)
  UTF8BOM:              array [0..2] of AnsiChar = #$EF#$BB#$BF;
  UTF16LittleEndianBOM: array [0..1] of AnsiChar = #$FF#$FE;
  UTF16BigEndianBOM:    array [0..1] of AnsiChar = #$FE#$FF;
  UTF32LittleEndianBOM: array [0..3] of AnsiChar = #$FF#$FE#$00#$00;
  UTF32BigEndianBOM:    array [0..3] of AnsiChar = #$00#$00#$FE#$FF;

function FileHasUnicodeBOM(const FileName: string): Boolean;
var
  Buffer: array [0..3] of AnsiChar;
  Stream: TFileStream;
begin
  Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); // Allow other programs read access at the same time.
  Try
    FillChar(Buffer, SizeOf(Buffer), $AA);//fill with characters that we are not expecting then...
    Stream.Read(Buffer, SizeOf(Buffer));  //...read up to SizeOf(Buffer) bytes - there may not be enough
    //use Read rather than ReadBuffer so the no exception is raised if we can't fill Buffer
  Finally
    FreeAndNil(Stream);
  End;
  Result := CompareMem(@UTF8BOM,              @Buffer, SizeOf(UTF8BOM))              or
            CompareMem(@UTF16LittleEndianBOM, @Buffer, SizeOf(UTF16LittleEndianBOM)) or
            CompareMem(@UTF16BigEndianBOM,    @Buffer, SizeOf(UTF16BigEndianBOM))    or
            CompareMem(@UTF32LittleEndianBOM, @Buffer, SizeOf(UTF32LittleEndianBOM)) or
            CompareMem(@UTF32BigEndianBOM,    @Buffer, SizeOf(UTF32BigEndianBOM));
end;

这将检测所有标准的BOM。如果您希望阻止此类文件,则可以使用它。

您说Delphi 6的TStringList可以加载16位编码的文件,如果它们没有BOM。虽然可能是这种情况,但是对于ASCII范围内的字符,每隔一个字符就是#0。我猜这不是你想要的。

如果您想检测文本是否为无BOM文件的Unicode,则可以使用IsTextUnicode。但是,它可能会出现误报。这是一种情况,我认为寻求原谅比征得允许更好。

现在,如果我是您,我实际上不会尝试阻止Unicode文件。我会读取它们。使用TNT Unicode库。您需要的类名为TWideStringList


1
“检测Unicode”是一个相当大胆的说法,你的代码只能检测BOM的存在,并且可以打开任何没有BOM的文件。 - OnTheFly
@Matheus Freitas,我不知道你在说什么。 显然你已经对你的答案感到满意了,它大胆地“检测Unicode” :-) - OnTheFly
@DavidHeffernan 现在,我只是想为将来的参考而说一下,经过一些阅读,我现在能够稍微了解一点关于Unicode的知识。提供的函数没有解决问题,因为用户发送给我没有BOM的文件。解决方案:没有。我实际上告诉他将这些文件编码为ANSI(或UTF-8),因为我正在将应用程序移植到Delphi的unicode版本。提供的函数确实是正确的,它做到了它所说的,也就是检测Unicode BOM的存在。 - EProgrammerNotFound
@DavidHeffernan 我告诉用户也要使用UTF-8(不带BOM),因为发送给我的所有数据都是本地名称(例如不使用中文字符)和数字。从未发生过越过ASCII限制的情况。 - EProgrammerNotFound
@DavidHeffernan 是的,没错。问题是,几个月前我甚至不知道 Unicode 的存在。我仍在学习它。但我相信像你说的那样达成一致是个好主意。 - EProgrammerNotFound
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接