2009-03-19 2 views
6

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

Это очень хорошо, но по-прежнему не хватает времени. (Многоязычные файлы)

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

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

Что было бы лучшим способом реализовать что-то подобное?


Редактировать: Похоже, я не проявил себя достаточно ясно. «Циклическим путем через кодирование», я не имею в виду «как закодировать кодировки»?

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

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

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

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


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

+0

Технически, кодированный файл UTF-8 не нуждается в спецификации. Это даже обескураживает, так как это будет мешать приложениям, которые ожидают, что данные ASCII начнутся с определенных символов, например «#!» в начале скриптов оболочки Unix. –

ответ

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 (данные) для дальнейшей обработки.

0

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

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

0

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

0

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

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

Использование LoadFile на вашей первой попытки; затем используйте TryEncoding.

+0

Вам не нужно перезагружать поток памяти, то есть stream.Seek (0, SeekOrigin.Begin)? –

+0

Наверное - просто написал это в блокноте :) –

4

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

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

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

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

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