private bool Read() { if (!_isHeaderReaded) { ReadHeaderRow(); _isHeaderReaded = true; } if (Reader.EndOfStream) { return(false); } var fields = ReadRow(); if (fields.Length != _headers.Count) { throw new CsvReadingException("Invalid row. Fields are not accepts to headers"); } CurrentRecord = new CsvRecord(); for (var i = 0; i < _headers.Count; i++) { CurrentRecord.Add(_headers.ElementAt(i), fields[i]); } return(true); }
/// <summary> /// Parses the line into a list of strings. /// </summary> /// <param name="line">The line.</param> /// <returns></returns> public static CsvRecord ParseLine(string line) { var values = new CsvRecord(); var currentValue = new StringBuilder(1024); char currentChar; Nullable <char> nextChar = null; var currentState = ReadState.WaitingForNewField; for (var charIndex = 0; charIndex < line.Length; charIndex++) { // Get the current and next character currentChar = line[charIndex]; nextChar = charIndex < line.Length - 1 ? line[charIndex + 1] : new Nullable <char>(); // Perform logic based on state and decide on next state switch (currentState) { case ReadState.WaitingForNewField: { currentValue.Clear(); if (currentChar == DoubleQuote) { currentState = ReadState.PushingQuoted; continue; } else if (currentChar == Comma) { values.Add(currentValue.ToString()); currentState = ReadState.WaitingForNewField; continue; } else { currentValue.Append(currentChar); currentState = ReadState.PushingNormal; continue; } } case ReadState.PushingNormal: { // Handle field content delimiter by comma if (currentChar == Comma) { currentState = ReadState.WaitingForNewField; values.Add(currentValue.ToString().Trim()); currentValue.Clear(); continue; } // Handle double quote escaping if (currentChar == DoubleQuote && nextChar == DoubleQuote) { // advance 1 character now. The loop will advance one more. currentValue.Append(currentChar); charIndex++; continue; } currentValue.Append(currentChar); break; } case ReadState.PushingQuoted: { // Handle field content delimiter by ending double quotes if (currentChar == DoubleQuote && nextChar != DoubleQuote) { currentState = ReadState.PushingNormal; continue; } // Handle double quote escaping if (currentChar == DoubleQuote && nextChar == DoubleQuote) { // advance 1 character now. The loop will advance one more. currentValue.Append(currentChar); charIndex++; continue; } currentValue.Append(currentChar); break; } } } // push anything that has not been pushed (flush) values.Add(currentValue.ToString().Trim()); return(values); }
public static CsvRecord[] GetRecords(string content, string delimiter) { List <CsvRecord> records = new List <CsvRecord>(); //List<string> fields = new List<string>(); content = content + "\n"; var charArray = content.ToArray(); //the following variables are used in the for loop. var currentField = string.Empty; var concatenating = true; //meaning we are concatenating a field. or to say, we find the start but we are not at the end of a field yet. var startWithDoubleQuote = false; var startRecord = true; var currentRecord = new CsvRecord(); records.Add(currentRecord); for (int i = 0; i < charArray.Length; i++) { var currentChar = charArray[i]; var nextChar = i + 1 < charArray.Length? charArray[i + 1] : '\0'; if (startRecord) { switch (currentChar) { case '\r': continue; case '\n': continue; case ',': currentRecord.Add(string.Empty); concatenating = false; break; case '"': startWithDoubleQuote = true; concatenating = true; break; default: currentField += currentChar; startWithDoubleQuote = false; concatenating = true; break; } startRecord = false; } else if (concatenating) { if (startWithDoubleQuote) { if (currentChar == '"') { //if this is the last char if (i + 1 == charArray.Length) { currentField += currentChar; AddField(currentRecord, ref currentField, ref concatenating); continue; } if (nextChar == '"') { currentField += currentChar; i++; } else //nextChar != '"' { AddField(currentRecord, ref currentField, ref concatenating); if (nextChar == ',') { i++; } } } else // currentChar!='"' { if (i + 1 == charArray.Length) { throw new CsvFormatException(); } currentField += currentChar; } } else //not startWithDoubleQuote { //if this is the last char if (i + 1 == charArray.Length) { currentField += currentChar; currentField = currentField.Trim(); currentRecord.Add(currentField); continue; } switch (currentChar) { case '\r': case '\n': currentRecord.Add(currentField); currentRecord = new CsvRecord(); currentField = string.Empty; records.Add(currentRecord); startRecord = true; continue; case ',': AddField(currentRecord, ref currentField, ref concatenating); break; default: currentField += currentChar; break; } } } else // not concatenating { switch (currentChar) { case '\r': case '\n': var previousChar = i > 0? charArray[i - 1]:'\0'; if (previousChar == ',') { currentRecord.Add(string.Empty); currentRecord = new CsvRecord(); records.Add(currentRecord); startRecord = true; } else { currentRecord = new CsvRecord(); records.Add(currentRecord); startRecord = true; } continue; case ',': currentRecord.Add(string.Empty); break; case '"': startWithDoubleQuote = true; concatenating = true; break; default: startWithDoubleQuote = false; concatenating = true; currentField += currentChar; break; } } } //checked if the last record is empty var last = records.Last(); var isEmpty = false; if (last.Count == 0) { isEmpty = true; } else { foreach (string s in last) { if (string.IsNullOrEmpty(s)) { isEmpty = true; break; } } } if (isEmpty) { records.Remove(last); } return(records.ToArray()); }
private static void AddField(CsvRecord currentRecord, ref string currentField, ref bool concatenating) { currentRecord.Add(currentField.Trim()); currentField = string.Empty; concatenating = false; }