2 * Karinto Library Project
\r
4 * This software is distributed under a zlib-style license.
\r
5 * See license.txt for more information.
\r
10 using System.Collections.Generic;
\r
12 using System.Text.RegularExpressions;
\r
17 public class CsvReader : CsvReader<DataTable>
\r
23 public CsvReader(DataTable prototype)
\r
29 public class CsvReader<TDataTable> where TDataTable : DataTable, new()
\r
31 #region private fields
\r
33 private string separator;
\r
34 private Regex sepPattern;
\r
35 private TDataTable prototype;
\r
36 private DataColumnCollection cols;
\r
38 public delegate bool Parser(ref string input, out object output);
\r
39 static private Dictionary<Type, Parser> parsers;
\r
40 private Parser[] lineParser;
\r
44 #region constructors
\r
47 parsers = new Dictionary<Type, Parser>();
\r
48 parsers[typeof(Boolean)] = ParseBoolean;
\r
49 parsers[typeof(Double)] = ParseDouble;
\r
50 parsers[typeof(Single)] = ParseSingle;
\r
51 parsers[typeof(Decimal)] = ParseDecimal;
\r
52 parsers[typeof(Int32)] = ParseInt32;
\r
53 parsers[typeof(Int64)] = ParseInt64;
\r
57 : this(new TDataTable())
\r
61 public CsvReader(TDataTable prototype)
\r
64 this.prototype = (TDataTable)prototype.Clone();
\r
65 cols = prototype.Columns;
\r
66 lineParser = new Parser[cols.Count];
\r
67 for (int i = 0; i < cols.Count; ++i)
\r
69 Type t = cols[i].DataType;
\r
70 if (parsers[t] != null)
\r
72 lineParser[i] = parsers[t];
\r
74 else if (t == typeof(DateTime))
\r
76 lineParser[i] = ParseDateTime;
\r
80 lineParser[i] = ParseString;
\r
91 public string Separator
\r
100 sepPattern = new Regex(separator, RegexOptions.Compiled);
\r
106 #region public methods
\r
108 public TDataTable Read(FilePath path)
\r
110 TDataTable table = (TDataTable)prototype.Clone();
\r
113 using (FileStream fs = new FileStream(
\r
114 path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
\r
116 using (StreamReader reader = new StreamReader(fs))
\r
118 while (reader.Peek() >= 0)
\r
120 DataRow row = table.NewRow();
\r
121 string line = reader.ReadLine();
\r
125 if (table.Rows.Count < 1)
\r
127 SetHeader(table.Columns, line);
\r
131 table.Rows.Add(row);
\r
136 catch (Exception ex)
\r
143 public TDataTable ReadAll(FilePath path)
\r
145 throw new NotImplementedException();
\r
149 public Parser GetParser(int column)
\r
151 return lineParser[column];
\r
154 public Parser GetParser(string column)
\r
156 return lineParser[prototype.Columns.IndexOf(column)];
\r
159 public Parser GetParser(DataColumn column)
\r
161 return lineParser[prototype.Columns.IndexOf(column.ColumnName)];
\r
164 static public Parser GetParser(Type type)
\r
166 return parsers[type];
\r
169 public void SetParser(int column, Parser parser)
\r
171 lineParser[column] = parser;
\r
174 public void SetParser(string column, Parser parser)
\r
176 lineParser[prototype.Columns.IndexOf(column)] = parser;
\r
179 public void SetParser(DataColumn column, Parser parser)
\r
181 lineParser[prototype.Columns.IndexOf(column.ColumnName)] = parser;
\r
184 static public void SetParser(Type type, Parser parser)
\r
186 parsers[type] = parser;
\r
193 #region private methods
\r
195 private void SetRow(DataRow row, string line)
\r
197 for (int i = 0; i < lineParser.Length; ++i)
\r
200 if (lineParser[i](ref line, out value))
\r
206 row.RowError = line;
\r
208 Match m = sepPattern.Match(line);
\r
209 line = line.Substring(m.Length);
\r
214 private void SetHeader(DataColumnCollection columns, string line)
\r
216 for (int i = 0; i < columns.Count; ++i)
\r
219 if (ParseString(ref line, out value))
\r
221 string name = value as string;
\r
222 Match comment = Regex.Match(name, @"^#\s*");
\r
223 columns[i].Caption = name.Substring(comment.Length);
\r
229 Match m = sepPattern.Match(line);
\r
230 line = line.Substring(m.Length);
\r
236 static private bool ParseBoolean(ref string input, out object output)
\r
238 Match m = Regex.Match(input,
\r
239 "^" + Boolean.TrueString, RegexOptions.IgnoreCase);
\r
242 m = Regex.Match(input,
\r
243 "^" + Boolean.FalseString, RegexOptions.IgnoreCase);
\r
251 input = input.Substring(m.Length);
\r
255 static private bool ParseDouble(ref string input, out object output)
\r
257 Match m = RegexSet.DecimalFloat.Match(input);
\r
263 output = Double.Parse(m.Groups[1].Value);
\r
264 input = input.Substring(m.Length);
\r
268 static private bool ParseSingle(ref string input, out object output)
\r
270 Match m = RegexSet.DecimalFloat.Match(input);
\r
276 output = Single.Parse(m.Groups[1].Value);
\r
277 input = input.Substring(m.Length);
\r
281 static private bool ParseDecimal(ref string input, out object output)
\r
283 Match m = RegexSet.DecimalFloat.Match(input);
\r
289 output = Decimal.Parse(m.Groups[1].Value);
\r
290 input = input.Substring(m.Length);
\r
294 static private bool ParseInt32(ref string input, out object output)
\r
296 Match m = RegexSet.DecimalFloat.Match(input);
\r
302 output = (Int32)Double.Parse(m.Groups[1].Value);
\r
303 input = input.Substring(m.Length);
\r
307 static private bool ParseInt64(ref string input, out object output)
\r
309 Match m = RegexSet.DecimalFloat.Match(input);
\r
315 output = (Int64)Double.Parse(m.Groups[1].Value);
\r
316 input = input.Substring(m.Length);
\r
320 private bool ParseDateTime(ref string input, out object output)
\r
323 ParseString(ref input, out value);
\r
325 if (DateTime.TryParse(value as string, out dt))
\r
330 output = DBNull.Value;
\r
334 private bool ParseString(ref string input, out object output)
\r
336 Match quotedMatch = RegexSet.QuotedString.Match(input);
\r
337 if (quotedMatch.Success)
\r
339 string content = quotedMatch.Groups[1].Value;
\r
340 output = content.Replace("\"\"", "\"");
\r
341 input = input.Substring(quotedMatch.Length);
\r
345 Match m = sepPattern.Match(input);
\r
348 output = input.Substring(0, m.Index);
\r
349 input = input.Substring(m.Index);
\r