ZZZSharePoint
ZZZSharePoint

Reputation: 1361

Reading csv file in c# method

I am aiming to read a csv file in my c# method. this csv file is not defined and it can have n number of columns. One thing which will always remain constant is that there will be only two rows in csv file. one will be header row and other will be value row. My below method works fine when my values are string values but fails when one of my value is something like this [test,test1,test2]. I tried with Csv helper class but I am unable to do. can someone suggest me how should I approach?

metadata is list of lines I read from StreamReader
private void AddValuesToTable( DynamicTableEntity tableEntry, List<string> metadata )
        {
           
            var headers = metadata[0].Split( "," );
            var values = metadata[1].Split( "," );
            for( int i = 0; i < headers.Count(); i++ )
            {
                tableEntry.Properties.Add( headers[i].ToString(), EntityProperty.CreateEntityPropertyFromObject( values[i] ) );
            }
        }

Sample value:

columnA,columnB,columnC
valA,[testa,testb],valc

Upvotes: 0

Views: 160

Answers (1)

Enigmativity
Enigmativity

Reputation: 117175

This is the code that I use to parse a CSV line.

private static string Peek(this string source, int peek) => (source == null || peek < 0) ? null : source.Substring(0, source.Length < peek ? source.Length : peek);
private static (string, string) Pop(this string source, int pop) => (source == null || pop < 0) ? (null, source) : (source.Substring(0, source.Length < pop ? source.Length : pop), source.Length < pop ? String.Empty : source.Substring(pop));

public static string[] ParseCsvLine(this string line)
{
    return ParseCsvLineImpl(line).ToArray();
    IEnumerable<string> ParseCsvLineImpl(string l)
    {
        string remainder = line;
        string field;
        while (remainder.Peek(1) != "")
        {
            (field, remainder) = ParseField(remainder);
            yield return field;
        }
    }
}

private const string DQ = "\"";

private static (string field, string remainder) ParseField(string line)
{
    if (line.Peek(1) == DQ)
    {
        var (_, split) = line.Pop(1);
        return ParseFieldQuoted(split);
    }
    else
    {
        var field = "";
        var (head, tail) = line.Pop(1);
        while (head != "," && head != "")
        {
            field += head;
            (head, tail) = tail.Pop(1);
        }
        return (field, tail);
    }
}

private static (string field, string remainder) ParseFieldQuoted(string line)
{
    var field = "";
    var head = "";
    var tail = line;
    while (tail.Peek(1) != "" && (tail.Peek(1) != DQ || tail.Peek(2) == DQ + DQ))
    {
        if (tail.Peek(2) == DQ + DQ)
        {
            (head, tail) = tail.Pop(2);
            field += DQ;
        }
        else
        {
            (head, tail) = tail.Pop(1);
            field += head;
        }
    }
    if (tail.Peek(2) == DQ + ",")
    {
        (head, tail) = tail.Pop(2);
    }
    else if (tail.Peek(1) == DQ)
    {
        (head, tail) = tail.Pop(1);
    }
    return (field, tail);
}

It correctly deals with quoted fields.

Upvotes: 3

Related Questions