2009-03-19 41 views
6

Tôi đang đọc các tệp ở nhiều định dạng và ngôn ngữ khác nhau và hiện tôi đang sử dụng thư viện mã hóa nhỏ để tìm cách phát hiện mã hóa thích hợp (http://www.codeproject.com/KB/recipes/DetectEncoding.aspx).C#: Chu kỳ thông qua mã hóa

Nó khá tốt, nhưng thỉnh thoảng nó vẫn bị lỡ. (Các tệp đa ngôn ngữ)

Hầu hết người dùng tiềm năng của tôi có rất ít hiểu biết về mã hóa (tốt nhất tôi có thể hy vọng là "nó có liên quan đến ký tự") và rất khó có thể chọn mã hóa phù hợp một danh sách, vì vậy tôi muốn để cho họ chu kỳ thông qua các mã hóa khác nhau cho đến khi một trong những quyền được tìm thấy chỉ bằng cách nhấp vào một nút.

Hiển thị sự cố? Nhấp vào đây để thử mã hóa khác! (Dù sao thì đó cũng là khái niệm)

Cách tốt nhất để thực hiện điều gì đó như thế?


Chỉnh sửa: Có vẻ như tôi không thể hiện bản thân mình đủ rõ ràng. Bằng cách "đi qua mã hóa", tôi không có nghĩa là "cách lặp qua mã hóa?"

Ý của tôi là "cách để người dùng thử mã hóa khác nhau theo thứ tự mà không cần tải lại tệp?"

Ý tưởng giống như sau: Giả sử tệp được tải bằng mã hóa sai. Một số ký tự lạ được hiển thị. Người dùng sẽ nhấp vào nút "Mã hóa tiếp theo" hoặc "mã hóa trước" và chuỗi sẽ được chuyển đổi bằng mã hóa khác. Người dùng chỉ cần tiếp tục nhấp cho đến khi mã hóa đúng được tìm thấy. (bất kỳ mã hóa nào tốt cho người dùng sẽ làm tốt). Miễn là người dùng có thể nhấp vào "tiếp theo", anh ấy có cơ hội hợp lý để giải quyết vấn đề của mình.

Những gì tôi đã tìm thấy liên quan đến việc chuyển đổi chuỗi thành byte bằng cách sử dụng mã hóa hiện tại, sau đó chuyển đổi byte sang mã hóa tiếp theo, chuyển đổi các byte thành ký tự, sau đó chuyển đổi char thành chuỗi ... Doable, nhưng tôi tự hỏi nếu không có cách nào dễ dàng hơn để làm điều đó.

Ví dụ: nếu có phương thức đọc chuỗi và trả về bằng cách sử dụng mã hóa khác, chẳng hạn như "hiển thị (chuỗi, mã hóa)".


Cảm ơn rất nhiều câu trả lời!

+0

Về mặt kỹ thuật, tệp được mã hóa UTF-8 không cần BOM. Nó thậm chí còn nản chí, vì nó sẽ can thiệp vào các ứng dụng mong đợi dữ liệu ASCII bắt đầu với các ký tự nhất định, như "#!" ở đầu tập lệnh hệ vỏ Unix. –

Trả lời

14

Đọc tệp dưới dạng byte và sử dụng phương thức 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)); 

Vì vậy, bạn chỉ phải tải tệp một lần.Bạn có thể sử dụng mọi mã hóa dựa trên byte gốc của tệp. Người dùng có thể chọn đúng một und bạn có thể sử dụng kết quả của Encoding.GetEncoding (...) GetString (dữ liệu) để xử lý tiếp.

0

Bạn có thể cho phép người dùng nhập một số từ (có ký tự "đặc biệt") được cho là xảy ra trong tệp không?

Bạn có thể tự tìm kiếm tất cả mã hóa để xem những từ này có hiện diện hay không.

0

Cảnh giác với 'Notepad bug' khét tiếng '. Nó sẽ cắn bạn bất cứ điều gì bạn cố gắng, mặc dù ... Bạn có thể tìm thấy một số good discussions về mã hóa và những thách thức của họ trên MSDN (và những nơi khác).

0

Bạn phải giữ dữ liệu gốc dưới dạng mảng byte hoặc MemoryStream, sau đó bạn có thể dịch sang mã hóa mới, khi bạn đã chuyển đổi dữ liệu thành chuỗi, bạn không thể quay trở lại biểu diễn gốc một cách đáng tin cậy.

0

Làm thế nào về một cái gì đó như thế này:

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

Sử dụng LoadFile trong lần thử đầu tiên của bạn; sau đó sử dụng TryEncoding sau đó.

+0

Bạn không cần phải đặt lại luồng bộ nhớ, ví dụ: stream.Seek (0, SeekOrigin.Begin)? –

+0

Có lẽ - chỉ cần viết nó lên trong notepad :) –

4

(lấy câu trả lời ban đầu sau cập nhật câu hỏi)

Ví dụ, nếu có một phương pháp mà có thể đọc một chuỗi và trả lại sử dụng một mã hóa khác nhau, một cái gì đó như "render (chuỗi, mã hóa) ".

Tôi không nghĩ bạn có thể sử dụng lại dữ liệu chuỗi. Thực tế là: nếu mã hóa sai, chuỗi này có thể bị coi là bị hỏng. Nó có thể rất dễ dàng có chứa vô nghĩa trong số các nhân vật có khả năng tìm kiếm. Đặc biệt, nhiều mã hóa có thể tha thứ cho sự hiện diện/vắng mặt của một BOM/phần mở đầu, nhưng bạn sẽ mã hóa lại với nó? không có nó?

Nếu bạn đang hạnh phúc có nguy cơ nó (tôi sẽ không), bạn có thể chỉ cần tái mã hóa chuỗi địa phương với encode lần cuối:

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

Trong thực tế, tôi tin là tốt nhất bạn có thể làm là giữ nguyên bản gốc byte[] - tiếp tục cung cấp các kết xuất khác nhau (thông qua các mã hóa khác nhau) cho đến khi chúng giống nhau. Một cái gì đó như:

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(); 
       } 
      } 
     }; 
    } 
} 
Các vấn đề liên quan