Last active
October 2, 2024 11:02
-
-
Save DevPoint/ddba1ed0be307b05e6ac7a483a63a4e5 to your computer and use it in GitHub Desktop.
C# implementation of a CSV reader which generates a two dimensional cells array of strings out of an CSV file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Devpoint | |
{ | |
public class CsvReader | |
{ | |
private readonly StringBuilder _cellBuilder; | |
private readonly List<string> _cellCache; | |
public CsvReader() | |
{ | |
_cellBuilder = new StringBuilder(200); | |
_cellCache = new List<string>(20); | |
} | |
public string[] ReadRow( | |
string inputLine, char delimiter, char textQualifier = '"') | |
{ | |
if (!string.IsNullOrEmpty(inputLine)) | |
{ | |
// parse input line | |
int inputIndex = 0; | |
bool textQualifierOpened = false; | |
while (inputIndex < inputLine.Length) | |
{ | |
char c = inputLine[inputIndex]; | |
if (c == delimiter && !textQualifierOpened) | |
{ | |
_cellCache.Add(_cellBuilder.ToString()); | |
_cellBuilder.Clear(); | |
inputIndex += 1; | |
} | |
else if (c == '\r' && !textQualifierOpened) | |
{ | |
_cellCache.Add(_cellBuilder.ToString()); | |
_cellBuilder.Clear(); | |
inputIndex += 1; | |
if (inputIndex < inputLine.Length && | |
inputLine[inputIndex] == '\n') | |
{ | |
inputIndex += 1; | |
} | |
} | |
else if (c == '\n' && !textQualifierOpened) | |
{ | |
_cellCache.Add(_cellBuilder.ToString()); | |
_cellBuilder.Clear(); | |
inputIndex += 1; | |
} | |
else if (c == textQualifier) | |
{ | |
if (inputIndex + 1 < inputLine.Length && | |
inputLine[inputIndex + 1] == textQualifier) | |
{ | |
_cellBuilder.Append(c); | |
inputIndex += 2; | |
} | |
else | |
{ | |
textQualifierOpened = !textQualifierOpened; | |
inputIndex += 1; | |
} | |
} | |
else if (char.IsHighSurrogate(c)) | |
{ | |
_cellBuilder.Append(c); | |
_cellBuilder.Append(inputLine[inputIndex + 1]); | |
inputIndex += 2; | |
} | |
else | |
{ | |
_cellBuilder.Append(c); | |
inputIndex += 1; | |
} | |
} | |
// add remaining to cell cache | |
if (_cellBuilder.Length > 0) | |
{ | |
_cellCache.Add(_cellBuilder.ToString()); | |
_cellBuilder.Clear(); | |
} | |
} | |
// return result | |
string[] result = _cellCache.ToArray(); | |
_cellCache.Clear(); | |
return result; | |
} | |
public string[] ReadRow( | |
StreamReader input, char delimiter, char textQualifier = '"') | |
{ | |
return ReadRow(input.ReadLine(), delimiter, textQualifier); | |
} | |
public async Task<string[]> ReadRowAsync( | |
StreamReader input, char delimiter, char textQualifier = '"') | |
{ | |
return ReadRow(await input.ReadLineAsync(), delimiter, textQualifier); | |
} | |
public string[][] ReadRows( | |
StreamReader input, char delimiter, char textQualifier = '"') | |
{ | |
var result = new List<string[]>(50); | |
string inputLine = input.ReadLine(); | |
while (!string.IsNullOrEmpty(inputLine)) | |
{ | |
result.Add(ReadRow(inputLine, delimiter, textQualifier)); | |
inputLine = input.ReadLine(); | |
} | |
return result.ToArray(); | |
} | |
public async Task<string[][]> ReadRowsAsync( | |
StreamReader input, char delimiter, char textQualifier = '"') | |
{ | |
var result = new List<string[]>(50); | |
string inputLine = await input.ReadLineAsync(); | |
while (!string.IsNullOrEmpty(inputLine)) | |
{ | |
result.Add(ReadRow(inputLine, delimiter, textQualifier)); | |
inputLine = await input.ReadLineAsync(); | |
} | |
return result.ToArray(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment