private void AddCell(FakeStack stack, ref List <string> columns, ref bool newCell, ref bool qualifierStart, ref bool qualifierEnd) { var parts = new List <string>(); while (stack.Count > 0) { string txt = stack.Pop(); if (txt != null) { if (_enableQualification) { if (txt.Length == 2 && txt[0].Equals(Settings.TextQualifier) && txt[1].Equals(Settings.TextQualifier)) { txt = _qualiferString; parts.Add(txt); } else if (txt.Length != 1 || !txt[0].Equals(Settings.TextQualifier) || IsQualifierStarted(qualifierStart, qualifierEnd)) { parts.Add(txt); } } else { parts.Add(txt); } } } if (columns == null) { columns = new List <string>(); } string val = string.Empty; if (parts.Count > 2) { var sbuf = new StringBuilder(); for (int i = parts.Count - 1; i >= 0; --i) { sbuf.Append(parts[i]); } val = sbuf.ToString(); } else { val = string.Concat(parts.Reverse <string>()); } if (val.Equals(Settings.NullValue) && !IsQualifierEnded(qualifierStart, qualifierEnd)) { val = null; } columns.Add(val); newCell = true; qualifierEnd = qualifierStart = false; }
/// <summary> /// Reads one row in the stream. Does not care whether there are carriage returns or not. /// </summary> /// <returns></returns> private string[] ReadRow() { if (PeekChar() < 0) { return(null); } List <string> columns = null; var stack = new FakeStack(); char c = '\0'; bool qualifierStart = false; bool qualifierEnd = false; bool newCell = true; // common operations anonymous helper method // for a better readability of the algorithm // Line parsing while (PeekChar() >= 0) { c = (char)ReadChar(); if (newCell) { // starting new cell newCell = false; if (IsNewLine(c)) { // empty row stack.Push(string.Empty); break; } else if (IsCarriageReturn(c)) { // empty row if (PeekNewLine()) { //discard ReadChar(); } stack.Push(string.Empty); break; } else if (IsQualifier(c)) { // text qualified cell qualifierStart = true; } else if (!IsSeparator(c)) { // first character stack.Push(c); } else { // empty cell AddCell(stack, ref columns, ref newCell, ref qualifierStart, ref qualifierEnd); } } // Text qualifier else if (IsQualifier(c)) { // process text qualifier if (PeekQualifier(stack) && IsQualifierStarted(qualifierStart, qualifierEnd)) { // needs escaping // escaped quotes will be resolved when the cell is assembled stack.Pop(); PushEscapedQualifier(stack); } else { // add qualifier on the stack stack.Push(c); } } // Other characters else { // process regular characters if (PeekQualifier(stack) && IsQualifierStarted(qualifierStart, qualifierEnd)) { // last qualifier is the closing qualifier stack.Pop(); stack.Push(string.Empty); qualifierEnd = true; } // old mac or windows EOL if (IsCarriageReturn(c) && !IsQualifierStarted(qualifierStart, qualifierEnd)) { if (PeekNewLine()) { //discard ReadChar(); } break; } // unix EOL else if (IsNewLine(c) && !IsQualifierStarted(qualifierStart, qualifierEnd)) { // end of row break; } else if (IsSeparator(c) && !IsQualifierStarted(qualifierStart, qualifierEnd)) { // end of cell AddCell(stack, ref columns, ref newCell, ref qualifierStart, ref qualifierEnd); } else { // add character on the stack stack.Push(c); } } } // left over cell if (stack.Count > 0 || IsSeparator(c)) { // last cell AddCell(stack, ref columns, ref newCell, ref qualifierStart, ref qualifierEnd); } string[] arr = null; if (columns.Count > 0) { arr = new string[columns.Count]; columns.CopyTo(arr); } return(arr); //return columns == null ? null : columns.ToArray(); }