private static string[] ParseCsv(TextReader reader, ref int lineNum, char separator) { var curChar = CharReader.Create(reader); if (curChar.IsEof) { return(null); // EOF reached } if (curChar.IsEol) { lineNum++; #if !FW452 return(Array.Empty <string>()); #else return(Array <string> .Empty); #endif } var result = new List <string>(); StringBuilder curField = null; var state = ParserState.ExpectField; var column = 1; while (true) { var skip = false; while (!skip) { switch (state) { case ParserState.ExpectField: if (curChar.IsEof || curChar.IsEol) { if (result.Count > 0) // Special case - empty string not treated as single empty value { result.Add(""); } return(result.ToArray()); } if (curChar.Char == separator) { result.Add(""); state = ParserState.AfterField; break; } skip = true; if (curChar.IsWhitespace) { break; } curField = new StringBuilder(); if (curChar.IsDoubleQuota) { state = ParserState.QuotedField; break; } state = ParserState.Field; curField.Append(curChar.Char); break; case ParserState.Field: Debug.Assert(curField != null, "curField != null"); if (curChar.IsEof || curChar.IsEol || curChar.Char == separator) { result.Add(curField.ToString().Trim()); state = ParserState.AfterField; break; } skip = true; curField.Append(curChar.Char); break; case ParserState.QuotedField: Debug.Assert(curField != null, "curField != null"); if (curChar.IsEof) { throw new FormatException($"Unexpected EOF at line {lineNum} column {column}"); } skip = true; if (curChar.IsEol) { curField.Append("\r\n"); break; } if (curChar.IsDoubleQuota) { var peek = curChar.Peek(); if (peek.IsDoubleQuota) // Escaped '"' { curField.Append('"'); curChar = curChar.Next(); } else { result.Add(curField.ToString()); state = ParserState.AfterField; } break; } curField.Append(curChar.Char); break; case ParserState.AfterField: if (curChar.IsEof || curChar.IsEol) { return(result.ToArray()); } skip = true; if (curChar.IsWhitespace) { continue; } if (curChar.Char == separator) { state = ParserState.ExpectField; break; } throw new FormatException($"Unexpected char '{curChar.Char}' at line {lineNum} column {column}"); default: throw new ArgumentOutOfRangeException(); } } curChar = curChar.Next(); column++; if (curChar.IsEol) { lineNum++; column = 1; } } }