C#:循环编码

时间:2009-03-19 10:43:06

标签: c# utf-8 character-encoding

我正在阅读各种格式和语言的文件,我目前正在使用一个小编码库来尝试检测正确的编码(http://www.codeproject.com/KB/recipes/DetectEncoding.aspx)。

这很不错,但偶尔还会错过。 (多语言文件)

我的大多数潜在用户对编码的理解很少(我希望最好的是“它与字符有关”)并且不太可能在列表中选择正确的编码,所以我我想让他们循环通过不同的编码,直到找到正确的编码只需点击一个按钮。

显示问题?点击这里尝试不同的编码! (无论如何这是概念)

实现类似内容的最佳方式是什么?


编辑:看起来我没有表达得足够清楚。通过“循环编码”,我不是指“如何循环编码?”

我的意思是“如何让用户按顺序尝试不同的编码而不重新加载文件?”

这个想法更像是这样的:假设文件加载了错误的编码。显示一些奇怪的字符。用户将单击“下一编码”或“先前编码”按钮,并且将以不同的编码转换该字符串。用户只需要一直点击,直到找到正确的编码。 (无论哪种编码看起来对用户有用都会很好)。只要用户点击“下一步”,他就有合理的机会解决他的问题。

到目前为止,我发现使用当前编码将字符串转换为字节,然后将字节转换为下一个编码,将这些字节转换为字符,然后将字符串转换为字符串......可行,但我想知道如果没有更简单的方法来做到这一点。

例如,如果有一个方法可以读取字符串并使用不同的编码返回它,例如“render(string,encoding)”。


非常感谢您的答案!

6 个答案:

答案 0 :(得分:14)

以字节形式读取文件,然后使用Encoding.GetString方法。

        byte[] data = System.IO.File.ReadAllBytes(path);

        Console.WriteLine(Encoding.UTF8.GetString(data));
        Console.WriteLine(Encoding.UTF7.GetString(data));
        Console.WriteLine(Encoding.ASCII.GetString(data));

所以你必须只加载一次文件。您可以根据文件的原始字节使用每个编码。用户可以选择正确的一个,你可以使用Encoding.GetEncoding(...)。GetString(data)的结果进行进一步处理。

答案 1 :(得分:4)

(删除问题更新后的原始答案)

  

例如,如果有方法   这将读取一个字符串并返回它   使用不同的编码,一些东西   比如“render(string,encoding)”。

我认为你不能重复使用字符串数据。事实是:如果编码错误,则此字符串可被视为已损坏。它可能很容易在可能看起来的角色中包含乱码。特别是,许多编码可能会原谅BOM /序言的存在/不存在,但是你会用它重新编码吗?没有它?

如果您愿意冒险(我不会),您可以使用上一次编码重新编码本地字符串:

// I DON'T RECOMMEND THIS!!!!
byte[] preamble = lastEncoding.GetPreamble(),
    content = lastEncoding.GetBytes(text);
byte[] raw = new byte[preamble.Length + content.Length];
Buffer.BlockCopy(preamble, 0, raw, 0, preamble.Length);
Buffer.BlockCopy(content, 0, raw, preamble.Length, content.Length);
text = nextEncoding.GetString(raw);

实际上,我相信你能做的最好的事情就是保持原来的byte[] - 继续提供不同的渲染(通过不同的编码),直到他们喜欢一个。类似的东西:

using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
class MyForm : Form {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
    ComboBox encodings;
    TextBox view;
    Button load, next;
    byte[] data = null;

    void ShowData() {
        if (data != null && encodings.SelectedIndex >= 0) {
            try {
                Encoding enc = Encoding.GetEncoding(
                    (string)encodings.SelectedValue);
                view.Text = enc.GetString(data);
            } catch (Exception ex) {
                view.Text = ex.ToString();
            }
        }
    }
    public MyForm() {
        load = new Button();
        load.Text = "Open...";
        load.Dock = DockStyle.Bottom;
        Controls.Add(load);

        next = new Button();
        next.Text = "Next...";
        next.Dock = DockStyle.Bottom;
        Controls.Add(next);

        view = new TextBox();
        view.ReadOnly = true;
        view.Dock = DockStyle.Fill;
        view.Multiline = true;
        Controls.Add(view);

        encodings = new ComboBox();
        encodings.Dock = DockStyle.Bottom;
        encodings.DropDownStyle = ComboBoxStyle.DropDown;
        encodings.DataSource = Encoding.GetEncodings();
        encodings.DisplayMember = "DisplayName";
        encodings.ValueMember = "Name";
        Controls.Add(encodings);

        next.Click += delegate { encodings.SelectedIndex++; };

        encodings.SelectedValueChanged += delegate { ShowData(); };

        load.Click += delegate {
            using (OpenFileDialog dlg = new OpenFileDialog()) {
                if (dlg.ShowDialog(this)==DialogResult.OK) {
                    data = File.ReadAllBytes(dlg.FileName);
                    Text = dlg.FileName;
                    ShowData();
                }
            }
        };
    }
}

答案 2 :(得分:0)

你可以让用户输入应该在文件中出现的一些单词(带有“特殊”字符)吗?

您可以自己搜索所有编码,看看这些单词是否存在。

答案 3 :(得分:0)

小心臭名昭着的'Notepad bug'。无论你尝试什么,它都会咬你,但是......你可以在MSDN(以及其他地方)找到一些关于编码及其挑战的good discussions

答案 4 :(得分:0)

您必须将原始数据保存为字节数组或MemoryStream,然后可以转换为新编码,一旦您已将数据转换为字符串,就无法可靠地返回到原始表示。

答案 5 :(得分:0)

这样的事情怎么样:

public string LoadFile(string path)
{
    stream = GetMemoryStream(path);     
    string output = TryEncoding(Encoding.UTF8);
}

public string TryEncoding(Encoding e)
{
    stream.Seek(0, SeekOrigin.Begin) 
    StreamReader reader = new StreamReader(stream, e);
    return reader.ReadToEnd();
}

private MemoryStream stream = null;

private MemorySteam GetMemoryStream(string path)
{
    byte[] buffer = System.IO.File.ReadAllBytes(path);
    return new MemoryStream(buffer);
}

第一次尝试使用加载文件;然后使用Try Encoding。