2008-08-07 43 views
15

cách điển hình của việc tạo ra một chuỗi CSV (giả):CSV chuỗi xử lý

  1. Tạo một đối tượng container CSV (giống như một StringBuilder trong C#).
  2. Lặp qua các chuỗi bạn muốn thêm gắn dấu phẩy sau mỗi chuỗi.
  3. Sau vòng lặp, hãy xóa dấu phẩy thừa cuối cùng đó.

Mã mẫu:

public string ReturnAsCSV(ContactList contactList) 
{ 
    StringBuilder sb = new StringBuilder(); 
    foreach (Contact c in contactList) 
    { 
     sb.Append(c.Name + ","); 
    } 

    sb.Remove(sb.Length - 1, 1); 
    //sb.Replace(",", "", sb.Length - 1, 1) 

    return sb.ToString(); 
} 

Tôi thích ý tưởng về cách thêm dấu phẩy bằng cách kiểm tra nếu container rỗng, nhưng không có nghĩa là xử lý nhiều như nó cần phải kiểm tra độ dài của chuỗi trên mỗi lần xuất hiện?

Tôi cảm thấy cần phải có cách xóa/xóa dấu phẩy cuối cùng dễ dàng hơn/sạch hơn. Ý tưởng nào?

Trả lời

19

Bạn có thể sử dụng LINQ to Objects:

string [] strings = contactList.Select(c => c.Name).ToArray(); 
string csv = string.Join(",", strings); 

Rõ ràng rằng tất cả có thể được thực hiện trong một dòng, nhưng nó rõ ràng hơn một chút trên hai.

+4

ít rõ ràng là nó không thực sự implem lấy đặc tả CSV. Đó là một cách tuyệt vời để đặt dấu phẩy vào một chuỗi, nhưng điều đó không giống như CSV, định dạng. – rcreswick

+0

Hoạt động tốt với hàm EncodeCsvField() được đăng bởi dbkk –

3

Thay vào đó, bạn có thể thêm dấu phẩy làm thứ đầu tiên bên trong foreach của mình.

if (sb.Length > 0) sb.Append(",");

0

Làm thế nào về việc theo dõi cho dù bạn là vào mục đầu tiên, và chỉ thêm một dấu phẩy trước mục nếu nó không phải là người đầu tiên.

public string ReturnAsCSV(ContactList contactList) 
{ 
    StringBuilder sb = new StringBuilder(); 
    bool isFirst = true; 

    foreach (Contact c in contactList) { 
     if (!isFirst) { 
      // Only add comma before item if it is not the first item 
      sb.Append(","); 
     } else { 
      isFirst = false; 
     } 

     sb.Append(c.Name); 
    } 

    return sb.ToString(); 
} 
0

Xin lỗi, ví dụ cụ thể về PHP, nhưng có thể giúp ai đó.

1

Tôi thích ý tưởng thêm dấu phẩy bằng cách kiểm tra xem vùng chứa có trống không, điều đó có nghĩa là xử lý nhiều hơn vì nó cần kiểm tra độ dài của chuỗi trên mỗi lần xuất hiện không?

Bạn đang tối ưu hóa sớm, hiệu suất đạt được sẽ không đáng kể.

3

Bạn cũng có thể tạo một mảng của c.Name dữ liệu và sử dụng phương thức String.Join để tạo đường của bạn.

public string ReturnAsCSV(ContactList contactList) 
{ 
    List<String> tmpList = new List<string>(); 

    foreach (Contact c in contactList) 
    { 
     tmpList.Add(c.Name); 
    } 

    return String.Join(",", tmpList.ToArray()); 
} 

Điều này có thể không được như performant như cách tiếp cận StringBuilder, nhưng nó chắc chắn có vẻ sạch hơn.

Ngoài ra, bạn có thể muốn xem xét sử dụng .CurrentCulture.TextInfo.ListSeparator thay vì dấu phẩy cứng - Nếu đầu ra của bạn sẽ được nhập vào các ứng dụng khác, bạn có thể gặp sự cố với nó. ListSeparator có thể khác nhau giữa các nền văn hóa khác nhau và ít nhất là MS Excel, tôn trọng cài đặt này.Vì vậy:

return String.Join(
    System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator, 
    tmpList.ToArray()); 
0

Làm thế nào về một số trang trí?

public string ReturnAsCSV(ContactList contactList) 
{ 
    StringBuilder sb = new StringBuilder(); 

    foreach (Contact c in contactList) 
    { 
     sb.Append(c.Name + ","); 
    } 

    return sb.ToString().Trim(','); 
} 
1

Chỉ cần một ý nghĩ, nhưng hãy nhớ để xử lý dấu phẩy dấu ngoặc kép (") và trong các giá trị lĩnh vực, nếu không tập tin CSV của bạn có thể phá vỡ các độc giả người tiêu dùng.

5

Đừng quên người bạn cũ của chúng tôi" cho ". nó không phải là đẹp trông như foreach nhưng nó có lợi thế của việc có thể bắt đầu từ phần tử thứ hai.

public string ReturnAsCSV(ContactList contactList) 
{ 
    if (contactList == null || contactList.Count == 0) 
     return string.Empty; 

    StringBuilder sb = new StringBuilder(contactList[0].Name); 

    for (int i = 1; i < contactList.Count; i++) 
    { 
     sb.Append(","); 
     sb.Append(contactList[i].Name); 
    } 

    return sb.ToString(); 
} 

Bạn cũng có thể quấn Nối thứ hai trong một 'nếu' mà kiểm tra cho dù thuộc tính Name chứa dấu ngoặc kép hoặc dấu phẩy và nếu có, hãy thoát chúng ra y.

9

Mã của bạn không thực sự tuân thủ với full CSV format. Nếu bạn chỉ tạo CSV từ dữ liệu không có dấu phẩy, dấu cách hàng đầu/dấu cách, tab, dòng mới hoặc dấu ngoặc kép thì sẽ ổn thôi. Tuy nhiên, trong hầu hết các tình huống trao đổi dữ liệu trong thế giới thực, bạn cần sự giải phóng hoàn toàn.

Đối với thế hệ này sang đúng CSV, bạn có thể sử dụng này:

public static String EncodeCsvLine(params String[] fields) 
{ 
    StringBuilder line = new StringBuilder(); 

    for (int i = 0; i < fields.Length; i++) 
    { 
     if (i > 0) 
     { 
      line.Append(DelimiterChar); 
     } 

     String csvField = EncodeCsvField(fields[i]); 
     line.Append(csvField); 
    } 

    return line.ToString(); 
} 

static String EncodeCsvField(String field) 
{ 
    StringBuilder sb = new StringBuilder(); 
    sb.Append(field); 

    // Some fields with special characters must be embedded in double quotes 
    bool embedInQuotes = false; 

    // Embed in quotes to preserve leading/tralining whitespace 
    if (sb.Length > 0 && 
     (sb[0] == ' ' || 
     sb[0] == '\t' || 
     sb[sb.Length-1] == ' ' || 
     sb[sb.Length-1] == '\t')) 
    { 
     embedInQuotes = true; 
    } 

    for (int i = 0; i < sb.Length; i++) 
    { 
     // Embed in quotes to preserve: commas, line-breaks etc. 
     if (sb[i] == DelimiterChar || 
      sb[i]=='\r' || 
      sb[i]=='\n' || 
      sb[i] == '"') 
     { 
      embedInQuotes = true; 
      break; 
     } 
    } 

    // If the field itself has quotes, they must each be represented 
    // by a pair of consecutive quotes. 
    sb.Replace("\"", "\"\""); 

    String rv = sb.ToString(); 

    if (embedInQuotes) 
    { 
     rv = "\"" + rv + "\""; 
    } 

    return rv; 
} 

Có thể không được mã hiệu quả nhất thế giới, nhưng nó đã được thử nghiệm. Thế giới thực hút so với mã mẫu nhanh :)

+0

Như được đăng trong một câu trả lời khác, có các thư viện để thực hiện điều này (ví dụ: OpenCSV) và chúng thực sự cũng có các thử nghiệm/thử nghiệm đơn vị. – rcreswick

+1

Hai chương trình con này cuối cùng đã giải quyết được vấn đề tôi đang theo đuổi. Đúng, lâu hơn một chút sau đó chỉ cần lick-và-dính tất cả các dữ liệu cùng với dấu phẩy, nhưng xử lý xuất khẩu hàng 400.000 của tôi mà không có vấn đề. – Lloyd

1

Tôi đã sử dụng phương pháp này trước đây. Thuộc tính Length của StringBuilder KHÔNG chỉ đọc để trừ nó bằng một phương tiện cắt ngắn ký tự cuối cùng. Nhưng bạn phải chắc chắn rằng chiều dài của bạn không phải là 0 để bắt đầu (điều này sẽ xảy ra nếu danh sách của bạn trống) vì việc thiết lập độ dài nhỏ hơn 0 là một lỗi.

public string ReturnAsCSV(ContactList contactList) 
{ 
    StringBuilder sb = new StringBuilder(); 

    foreach (Contact c in contactList)  
    { 
     sb.Append(c.Name + ",");  
    } 

    if (sb.Length > 0) 
     sb.Length -= 1; 

    return sb.ToString(); 
} 
5

Tại sao không sử dụng một trong các thư viện CSV nguồn mở không?

Tôi biết nó nghe có vẻ quá mức cần thiết cho một cái gì đó xuất hiện đơn giản, nhưng như bạn có thể nói bởi các bình luận và đoạn mã, có nhiều hơn đáp ứng mắt. Ngoài việc xử lý tuân thủ đầy đủ CSV, cuối cùng bạn sẽ muốn xử lý cả việc đọc và ghi CSV ... và bạn có thể muốn thao tác với tệp.

Tôi đã sử dụng Open CSV trên một trong các dự án của mình trước đây (nhưng có rất nhiều người khác để chọn). Nó chắc chắn làm cho cuộc sống của tôi dễ dàng hơn. ;)

1

Tôi đã viết một lớp học nhỏ cho điều này trong trường hợp ai đó tìm thấy nó hữu ích ...

public class clsCSVBuilder 
{ 
    protected int _CurrentIndex = -1; 
    protected List<string> _Headers = new List<string>(); 
    protected List<List<string>> _Records = new List<List<string>>(); 
    protected const string SEPERATOR = ","; 

    public clsCSVBuilder() { } 

    public void CreateRow() 
    { 
     _Records.Add(new List<string>()); 
     _CurrentIndex++; 
    } 

    protected string _EscapeString(string str) 
    { 
     return string.Format("\"{0}\"", str.Replace("\"", "\"\"") 
              .Replace("\r\n", " ") 
              .Replace("\n", " ") 
              .Replace("\r", " ")); 
    } 

    protected void _AddRawString(string item) 
    { 
     _Records[_CurrentIndex].Add(item); 
    } 

    public void AddHeader(string name) 
    { 
     _Headers.Add(_EscapeString(name)); 
    } 

    public void AddRowItem(string item) 
    { 
     _AddRawString(_EscapeString(item)); 
    } 

    public void AddRowItem(int item) 
    { 
     _AddRawString(item.ToString()); 
    } 

    public void AddRowItem(double item) 
    { 
     _AddRawString(item.ToString()); 
    } 

    public void AddRowItem(DateTime date) 
    { 
     AddRowItem(date.ToShortDateString()); 
    } 

    public static string GenerateTempCSVPath() 
    { 
     return Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString().ToLower().Replace("-", "") + ".csv"); 
    } 

    protected string _GenerateCSV() 
    { 
     StringBuilder sb = new StringBuilder(); 

     if (_Headers.Count > 0) 
     { 
      sb.AppendLine(string.Join(SEPERATOR, _Headers.ToArray())); 
     } 

     foreach (List<string> row in _Records) 
     { 
      sb.AppendLine(string.Join(SEPERATOR, row.ToArray())); 
     } 

     return sb.ToString(); 
    } 

    public void SaveAs(string path) 
    { 
     using (StreamWriter sw = new StreamWriter(path)) 
     { 
      sw.Write(_GenerateCSV()); 
     } 
    } 
} 
0

tôi sử dụng CSVHelper - đó là một thư viện mã nguồn mở tuyệt vời mà cho phép bạn tạo phù CSV suối một yếu tố tại một thời điểm hoặc tùy chỉnh bản đồ lớp học của bạn:

public string ReturnAsCSV(ContactList contactList) 
{ 
    StringBuilder sb = new StringBuilder(); 
    using (StringWriter stringWriter = new StringWriter(sb)) 
    { 
     using (var csvWriter = new CsvHelper.CsvWriter(stringWriter)) 
     { 
      csvWriter.Configuration.HasHeaderRecord = false; 
      foreach (Contact c in contactList) 
      { 
       csvWriter.WriteField(c.Name); 
      } 
     } 
    } 
    return sb.ToString(); 
} 

hoặc nếu bạn ánh xạ sau đó một cái gì đó như thế này: csvWriter.WriteRecords<ContactList>(contactList);

Các vấn đề liên quan