C #: цикл по кодировкам - PullRequest
6 голосов
/ 19 марта 2009

Я читаю файлы в различных форматах и ​​на разных языках, и в настоящее время я использую небольшую библиотеку кодирования, чтобы попытаться определить правильную кодировку (http://www.codeproject.com/KB/recipes/DetectEncoding.aspx).

Это довольно хорошо, но иногда все равно не хватает. (Многоязычные файлы)

Большинство моих потенциальных пользователей плохо разбираются в кодировке (лучшее, на что я могу надеяться, это «что-то связанное с символами»), и вряд ли я смогу выбрать правильную кодировку в списке, поэтому я хотел бы позволить им циклически проходить по разным кодировкам, пока не будет найдена правильная, просто нажав на кнопку.

Проблемы с отображением? Нажмите здесь, чтобы попробовать другую кодировку! (Ну, в любом случае, это концепция)

Как лучше всего реализовать что-то подобное?


Редактировать: Похоже, я недостаточно ясно выразился. Под "циклическим перемещением по кодированию" я не имею в виду "как проходить по кодировкам?"

Что я имел в виду, «как позволить пользователю попробовать разные кодировки в последовательности без перезагрузки файла?»

Идея больше похожа на это: допустим, файл загружен с неверной кодировкой. Некоторые странные символы отображаются. Пользователь нажимает кнопку «Следующая кодировка» или «предыдущая кодировка», и строка будет преобразована в другую кодировку. Пользователь просто должен нажимать, пока не будет найдена правильная кодировка. (какая бы кодировка ни казалась хорошей для пользователя, она подойдет) Пока пользователь может нажимать «далее», у него есть разумный шанс решить свою проблему.

То, что я нашел до сих пор, включает преобразование строки в байты с использованием текущей кодировки, затем преобразование байтов в следующую кодировку, преобразование этих байтов в символы, затем преобразование символа в строку ... Выполнимо, но мне интересно если нет более простого способа сделать это.

Например, если был метод, который считывал бы строку и возвращал ее, используя другую кодировку, что-то вроде «render (string, encoding)».


Большое спасибо за ответы!

Ответы [ 6 ]

14 голосов
/ 23 марта 2009

Считайте файл в байтах и ​​используйте метод 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) для дальнейшей обработки.

4 голосов
/ 23 марта 2009

(удален оригинальный ответ после обновления вопроса)

Например, если был метод что бы прочитать строку и вернуть ее используя другую кодировку, что-то как "рендер (строка, кодировка)".

Не думаю, что вы можете повторно использовать строковые данные. Дело в том, что если кодировка была неправильной, эту строку можно считать поврежденной. Это может очень легко содержать тарабарщину среди вероятных персонажей. В частности, многие кодировки могут простить наличие / отсутствие спецификации / преамбулы, но перекодировали бы ли вы ее? без этого?

Если вы рады рискнуть (я бы не стал), вы можете просто перекодировать вашу локальную строку с последней кодировкой:

// 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();
                }
            }
        };
    }
}
0 голосов
/ 23 марта 2009

Как насчет этого:

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.

0 голосов
/ 23 марта 2009

Вы должны сохранить исходные данные в виде байтового массива или MemoryStream, который затем можно преобразовать в новую кодировку, после того как вы уже преобразовали свои данные в строку, вы не можете надежно вернуться к исходному представлению.

0 голосов
/ 19 марта 2009

Остерегайтесь печально известной ошибки Notepad . Это будет кусать вас за то, что вы пытаетесь, хотя ... Вы можете найти несколько хороших обсуждений о кодировках и их проблемах в MSDN (и других местах).

0 голосов
/ 19 марта 2009

Не могли бы вы позволить пользователю ввести несколько слов (со "специальными" символами), которые должны встречаться в файле?

Вы можете самостоятельно выполнить поиск по всем кодировкам, чтобы узнать, присутствуют ли эти слова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...