4

我正在使用 FileUpload 服务器控件从 MS Word 上传以前保存的 HTML 文档(作为网页;过滤)。字符集是 windows-1252。该文档具有智能引号(卷曲)以及常规引号。它也有一些空格(显然),当深入观察时,它们是普通 TAB 或 SPACE 以外的字符。

在 StreamReader 中捕获文件内容时,这些特殊字符将转换为问号。我假设它是因为默认编码是 UTF-8 并且文件是 Unicode。

我继续使用 Unicode 编码创建了 StreamReader,然后用正确的字符替换了所有不需要的字符(我实际上在 stackoverflow 中找到的代码)。这似乎有效....只是我无法将字符串转换回 UTF-8 以在 asp:literal 中显示它。代码在那里,它应该可以工作....但是输出(ConvertToASCII)是不可读的。

请看下面:

    protected void btnUpload_Click(object sender, EventArgs e)
    {
        StreamReader sreader;
        if (uplSOWDoc.HasFile)
        {
            try
            {
                if (uplSOWDoc.PostedFile.ContentType == "text/html" || uplSOWDoc.PostedFile.ContentType == "text/plain")
                {
                    sreader = new StreamReader(uplSOWDoc.FileContent, Encoding.Unicode);
                    string sowText = sreader.ReadToEnd();
                    sowLiteral.Text = ConvertToASCII(sowText);
                    lblUploadResults.Text = "File loaded successfully.";
                }
                else
                    lblUploadResults.Text = "Upload failed. Just text or html files are allowed.";
            }
            catch(Exception ex)
            {
                lblUploadResults.Text = ex.Message;
            }
        }
    }

    private string ConvertToASCII(string source)
    {
        if (source.IndexOf('\u2013') > -1) source = source.Replace('\u2013', '-');
        if (source.IndexOf('\u2014') > -1) source = source.Replace('\u2014', '-');
        if (source.IndexOf('\u2015') > -1) source = source.Replace('\u2015', '-');
        if (source.IndexOf('\u2017') > -1) source = source.Replace('\u2017', '_');
        if (source.IndexOf('\u2018') > -1) source = source.Replace('\u2018', '\'');
        if (source.IndexOf('\u2019') > -1) source = source.Replace('\u2019', '\'');
        if (source.IndexOf('\u201a') > -1) source = source.Replace('\u201a', ',');
        if (source.IndexOf('\u201b') > -1) source = source.Replace('\u201b', '\'');
        if (source.IndexOf('\u201c') > -1) source = source.Replace('\u201c', '\"');
        if (source.IndexOf('\u201d') > -1) source = source.Replace('\u201d', '\"');
        if (source.IndexOf('\u201e') > -1) source = source.Replace('\u201e', '\"');
        if (source.IndexOf('\u2026') > -1) source = source.Replace("\u2026", "...");
        if (source.IndexOf('\u2032') > -1) source = source.Replace('\u2032', '\'');
        if (source.IndexOf('\u2033') > -1) source = source.Replace('\u2033', '\"');


        byte[] sourceBytes = Encoding.Unicode.GetBytes(source);
        byte[] targetBytes = Encoding.Convert(Encoding.Unicode, Encoding.ASCII, sourceBytes);
        char[] asciiChars = new char[Encoding.ASCII.GetCharCount(targetBytes, 0, targetBytes.Length)];
        Encoding.ASCII.GetChars(targetBytes, 0, targetBytes.Length, asciiChars, 0);

        string result = new string(asciiChars);

        return result;

    }

此外,正如我之前所说,还有一些更“透明”的字符似乎对应于单词 doc 具有编号缩进的位置,我不知道如何捕获它们的 unicode 值来替换它们......所以如果你有任何提示,请告诉我。

非常感谢提前!!

4

2 回答 2

6

根据MSDN 上的 StreamReader

StreamReader 对象尝试通过查看流的前三个字节来检测编码。如果文件以适当的字节顺序标记开头,它会自动识别 UTF-8、little-endian Unicode 和 big-endian Unicode 文本。否则,使用用户提供的编码。

因此,如果您上传的文件字符集是windows-1252,那么您的行:

sreader = new StreamReader(uplSOWDoc.FileContent, Encoding.Unicode);

不正确,因为文件内容不是 Unicode 编码的。相反,使用:

sreader = new StreamReader(uplSOWDoc.FileContent, 
                  Encoding.GetEncoding("Windows-1252"), true);

其中最终的布尔参数是检测 BOM

于 2011-03-15T22:21:12.937 回答
6
sreader = new StreamReader(uplSOWDoc.FileContent, Encoding.Unicode);

恭喜,你是被“Encoding.Unicode”咬伤的百万分之一的编码员。

没有“Unicode 编码”之类的东西。Unicode 是字符集,它有许多不同的编码。

Encoding.Unicode 实际上是特定的编码 UTF-16LE,其中字符被编码为 UTF-16 “代码单元”,然后每个 16 位代码单元以 little-endian 顺序写入字节。这是 Windows NT 的本机内存中 Unicode 字符串格式,但您几乎不想使用它来读取或写入文件。作为每单元 2 字节的编码,它与 ASCII 不兼容,并且对于存储或在线传输效率不高。

如今,UTF-8 是一种更常见的用于 Unicode 文本的编码。但微软将 UTF-16LE 误命名为“Unicode”继续迷惑和愚弄只想“支持 Unicode”的用户。由于 Encoding.Unicode 是一种不兼容 ASCII 的编码,因此尝试以 ASCII 超集编码(例如 UTF-8 或 Windows 默认代码页,如 1252 西欧)读取文件将使所有内容变得难以辨认,而不是只是非ASCII字符。

在这种情况下,您的文件存储在其中的编码是 Windows 代码页 1252。因此请阅读:

sreader= new StreamReader(uplSOWDoc.FileContent, Encoding.GetEncoding(1252));

我会把它留在那里。不要费心尝试“转换为 ASCII”。这些智能引号是非常好的字符,应该像任何其他 Unicode 字符一样受到支持;如果您在显示智能引号时遇到问题,那么您可能也在修改所有其他非 ASCII 字符。最好解决导致这种情况发生的问题,而不是试图在少数常见情况下避免它。

于 2011-03-17T01:23:35.810 回答