如何修复 Delphi 中字符集转换期间关于隐式字符串转换的这两个警告?

问题描述 投票:0回答:1

我写了一个合并不同文本文件的工具(文件很小)。文件可以是 ANSI (Latin1)、UTF-8(带或不带 BOM)。对于带有 BOM 的文件,Delphi 可以正确检测文件的字符集,但对于没有 BOM 的文件,我必须做一些黑客操作来检测字符集(参见

GetFileCharset
)。

在以下 Delphi 代码(我使用 Delphi 11)中,我收到 2 个警告(请参阅相关行末尾的注释):

uses
    WideStrUtils;
    

function GetFileCharset(const Filename: String): TEncoding;
var
    StreamReader: TStreamReader;
    FallbackEncoding: TEncoding;
    CurrLine: String;

begin
    FallbackEncoding := TEncoding.ANSI;

    try
        StreamReader := TStreamReader.Create(Filename, FallbackEncoding, True);
        try
            Result := StreamReader.CurrentEncoding;

            if StreamReader.CurrentEncoding = FallbackEncoding then
            begin
                while not StreamReader.EndOfStream do
                begin
                    CurrLine := StreamReader.ReadLine;
                    if IsUTF8String(CurrLine) then //[dcc32 Warning]: W1058 Implicit string cast with potential data loss from 'string' to 'RawByteString'
                    begin
                        Result := TEncoding.UTF8;
                        break;
                    end;
                end;
            end;
        finally
            StreamReader.Close;
            StreamReader.Free;
        end;
    except on E : Exception do
        Result := FallbackEncoding;
    end;
end;


StreamWriter := TStreamWriter.Create(OutputFile, False, TEncoding.UTF8);
try
    StreamReader := TStreamReader.Create(InputFile, GetFileCharset(CurrFile), True);
    try
        while not StreamReader.EndOfStream do
            StreamWriter.WriteLine(UTF8Encode(StreamReader.ReadLine)); //[dcc32 Warning]: W1057 Implicit string cast from 'RawByteString' to 'string'
    finally
        StreamReader.Close;
        StreamReader.Free;
    end;
finally
    StreamWriter.Close;
    StreamWriter.Free;
end;

#1 对于

Implicit string cast
警告,我可以轻松做到:

StreamWriter.WriteLine(String(UTF8Encode(StreamReader.ReadLine)));

但是我想知道是否有更好的方法或者这里是否有潜在的危险?

#2 对于

Implicit string cast with potential data loss
,我不知道如何安全地解决这个问题。

#3 有没有比我所做的更好的方法来检测文件字符集?

delphi unicode character-encoding
1个回答
0
投票

对于第一个警告:

StreamReader.ReadLine()
返回一个UTF-16编码的
UnicodeString
,它已经使用读者指定的
Encoding
进行了字符集解码(在您的情况下,always将是
TEncoding.ANSI
)。

IsUTF8String()
接受
RawByteString
并返回其原始字节是否以 UTF-8 编码。

当使用 16 位字符串而不是 8 位字符串调用

IsUTF8String()
时,您将获得隐式转换(此外,将
UnicodeString
转换为
RawByteString
是非 ASCII 字符的 lossy 转换,因此您一开始就不应该这样做)。

在您的情况下,

IsUTF8String()
never返回
True
,因为
UnicodeString
RawByteString
的转换将never产生UTF-8字符串。所以,你可以完全摆脱这个测试。

对于您正在尝试的内容,您需要分析文件的原始字节,而不是来自ReadLine()

解码字符
。此外,ASCII 是 ANSI 和 UTF-8 的子集,两者的编码完全相同,因此您需要分析整个文件(或至少直到遇到非 ASCII 字符)才能确定字符集正确。


对于第二次警告:

StreamWriter.WriteLine()
接受 UTF-16
UnicodeString
作为输入,但您改为向其传递 UTF-8
RawByteString
。您的解决方法只是使转换变得明确,但不会改变结果。虽然这是一种无损转换,但您实际上根本不需要
UTF8Encode()
。让
StreamWriter
在内部为您处理 UTF-8。

© www.soinside.com 2019 - 2024. All rights reserved.