Thanks a lot for that!
I modified the class to:
- use a variable delimiter, instead of hardcoded in code
- replacing all
newLines (\n \r \n\r) in
MakeValueCsvFriendly
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
public class CsvExport
{
public char delim = ';';
///
/// To keep the ordered list of column names
///
List fields = new List();
///
/// The list of rows
///
List> rows = new List>();
///
/// The current row
///
Dictionary currentRow { get { return rows[rows.Count - 1]; } }
///
/// Set a value on this column
///
public object this[string field]
{
set
{
// Keep track of the field names, because the dictionary loses the ordering
if (!fields.Contains(field)) fields.Add(field);
currentRow[field] = value;
}
}
///
/// Call this before setting any fields on a row
///
public void AddRow()
{
rows.Add(new Dictionary());
}
///
/// Converts a value to how it should output in a csv file
/// If it has a comma, it needs surrounding with double quotes
/// Eg Sydney, Australia -> "Sydney, Australia"
/// Also if it contains any double quotes ("), then they need to be replaced with quad quotes[sic] ("")
/// Eg "Dangerous Dan" McGrew -> """Dangerous Dan"" McGrew"
///
string MakeValueCsvFriendly(object value)
{
if (value == null) return "";
if (value is INullable && ((INullable)value).IsNull) return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString("yyyy-MM-dd");
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
string output = value.ToString();
if (output.Contains(delim) || output.Contains("\""))
output = '"' + output.Replace("\"", "\"\"") + '"';
if (Regex.IsMatch(output, @"(?:\r\n|\n|\r)"))
output = string.Join(" ", Regex.Split(output, @"(?:\r\n|\n|\r)"));
return output;
}
///
/// Output all rows as a CSV returning a string
///
public string Export()
{
StringBuilder sb = new StringBuilder();
// The header
foreach (string field in fields)
sb.Append(field).Append(delim);
sb.AppendLine();
// The rows
foreach (Dictionary row in rows)
{
foreach (string field in fields)
sb.Append(MakeValueCsvFriendly(row[field])).Append(delim);
sb.AppendLine();
}
return sb.ToString();
}
///
/// Exports to a file
///
public void ExportToFile(string path)
{
File.WriteAllText(path, Export());
}
///
/// Exports as raw UTF8 bytes
///
public byte[] ExportToBytes()
{
return Encoding.UTF8.GetBytes(Export());
}
}