C #: Ciclo através de codificações

votos
6

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 parecido?


Edit: Parece que eu não me expressar com clareza suficiente. Por bicicleta pela codificação, 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 que seja a 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 eu me pergunto se lá isn 't 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!

Publicado 19/03/2009 em 11:43
fonte usuário
Em outras línguas...                            


6 respostas

votos
14

Leia o arquivo como bytes e usar então 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 posterior processamento.

Respondeu 23/03/2009 em 14:09
fonte usuário

votos
4

(Removido resposta original seguinte actualização questão)

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)".

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 o último encoding:

// 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 você pode fazer é manter o original byte[]- continuar a oferecer diferentes representações (via codificações diferentes) até que eles gostam 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();
                }
            }
        };
    }
}
Respondeu 23/03/2009 em 14:38
fonte usuário

votos
0

Que tal algo como isso:

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, utilizar TryEncoding subsequentemente.

Respondeu 23/03/2009 em 14:14
fonte usuário

votos
0

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 cadeia que não pode voltar com segurança para a representação inicial.

Respondeu 23/03/2009 em 13:58
fonte usuário

votos
0

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

Respondeu 19/03/2009 em 13:24
fonte usuário

votos
0

você pode 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.

Respondeu 19/03/2009 em 11:53
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more