繁体   English   中英

C#:循环编码

[英]C#: Cycle through encodings

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

挺好看的,就是偶尔会漏掉。 (多语言文件)

我的大多数潜在用户对编码知之甚少(我最希望的是“它与字符有关”)并且不太可能能够在列表中选择正确的编码,所以我想让他们循环使用不同的编码,直到通过单击按钮找到正确的编码。

显示问题? 单击此处尝试不同的编码! (反正就是这个概念)

实现这样的事情的最佳方法是什么?


编辑:看起来我表达得不够清楚。 通过“循环编码”,我的意思不是“如何循环编码?”

我的意思是“如何让用户在不重新加载文件的情况下依次尝试不同的编码?”

这个想法更像是这样:假设文件加载了错误的编码。 显示一些奇怪的字符。 用户将单击“下一个编码”或“上一个编码”按钮,字符串将被转换为不同的编码。 用户只需要继续点击,直到找到正确的编码。 (任何对用户来说看起来不错的编码都可以)。 只要用户可以点击“下一步”,他就有合理的机会解决他的问题。

到目前为止我发现涉及使用当前编码将字符串转换为字节,然后将字节转换为下一个编码,将这些字节转换为字符,然后将字符转换为字符串......可行,但我想知道是否有这不是更简单的方法。

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


非常感谢您的回答!

将文件读取为字节,然后使用 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));

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

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

例如,如果有一个方法可以读取字符串并使用不同的编码返回它,比如“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();
                }
            }
        };
    }
}

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

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

当心臭名昭著的“记事本错误”。 不过,无论您尝试什么,它都会让您吃尽苦头……您可以在 MSDN(和其他地方)上找到有关编码及其挑战的一些很好的讨论

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

像这样的东西怎么样:

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);
}

第一次尝试使用 LoadFile; 然后随后使用 TryEncoding。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM