Pergunta

Eu estou lendo arquivos em vários formatos e línguas e eu estou usando atualmente uma pequena biblioteca de codificação para tomar tentativa de detectar a codificação adequada ( http://www.codeproject.com/KB/recipes/DetectEncoding.aspx ).

É muito bom, mas ainda perde de vez em quando. (Arquivos multilingue)

A maioria dos meus potenciais usuários têm muito pouca compreensão de codificação (o melhor que podemos esperar é "que tem algo a ver com caracteres") e são muito pouco provável que seja capaz de escolher a codificação direito em uma lista, então eu gostaria de deixá-los percorrer diferentes codificações até que o caminho certo é encontrado apenas clicando em um botão.

problemas de exibição? Clique aqui para tentar uma codificação diferente! (Bem, isso é o conceito de qualquer maneira)

Qual seria a melhor maneira de implementar algo assim?


Edit: Parece que eu não me expressar com clareza suficiente. Por "bicicleta pela codificação", eu não quero dizer "como fazer um loop através de codificações?"

O que eu quis dizer foi "como permitir que o usuário tente codificações diferentes em sequência sem recarregar o arquivo?"

A idéia é mais assim: digamos que o arquivo é carregado com a codificação errada. Alguns caracteres estranhos são exibidos. O usuário clica em um botão "Next codificação" ou "codificação anterior", ea cadeia seria convertido em uma codificação diferente. O usuário só precisa manter clicando até que a codificação correta é encontrada. (Qualquer codificação parece ser bom para o usuário vai fazer bem). Enquanto o usuário pode clicar em "Next", ele tem uma chance razoável de resolver o seu problema.

O que eu encontrei até agora envolve a conversão da cadeia para bytes utilizando a codificação corrente, em seguida, converter os bytes para o próximo codificação, converter esses bytes em caracteres, em seguida, converter o caractere em uma string ... factível, mas I maravilha se não houver uma maneira mais fácil de fazer isso.

Por exemplo, se houvesse um método que iria ler uma string e devolvê-lo usando uma codificação diferente, algo como "render (string, encoding)".


Muito obrigado pelas respostas!

Foi útil?

Solução

Leia o arquivo como bytes e uso, em seguida, o método 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));

Então você tem que carregar o arquivo apenas uma vez. Você pode usar todos os codificação com base nos bytes originais do arquivo. O usuário pode selecionar o correto und você pode usar o resultado de Encoding.GetEncoding (...). GetString (dados) para processamento posterior.

Outras dicas

(resposta original removido seguinte atualização questão)

Por exemplo, se havia um método que iria ler uma string e devolvê-lo usando uma codificação diferente, algo como "render (string, encoding)".

Eu não acho que você pode reutilizar os dados de cadeia. O fato é: se a codificação estava errado, essa seqüência pode ser considerado corrupto. Pode muito facilmente conter jargão entre os personagens provável que procuram. Em particular, muitos codificações pode perdoar a presença / ausência de um BOM / preâmbulo, mas você re-codificar com ele? sem ele?

Se você está feliz em arriscar (eu não seria), você pode simplesmente re-codificar a cadeia local, com a última codificação:

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

Na realidade, acredito que o melhor que pode fazer é manter a byte[] original - continuam oferecendo diferentes representações (via codificações diferentes) até que eles como um. Algo como:

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

Você poderia permitir que o usuário digite algumas palavras (com caracteres "especiais") que devem ocorrer no arquivo?

Você pode pesquisar todas as codificações-se para ver se estas palavras estão presentes.

Cuidado com o infame ' Notepad bug '. Vai a morder-lhe tudo o que você tente, embora ... Você pode encontrar alguns boas discussões sobre codificações e seus desafios no MSDN (e outros lugares).

Você tem que manter os dados originais como um array de bytes ou MemoryStream você pode então traduzir para a nova codificação, uma vez que você já converteu os seus dados para uma string que você não pode voltar com segurança para a representação inicial.

Como sobre algo como isto:

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

Use LoadFile em sua primeira tentativa; em seguida, usar TryEncoding posteriormente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top