0

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
5
  • Your question seems a little vague. What type of values are making your method fail ? Do you always intend to have 2 comma-separated values in metadata[1] ? Commented Mar 5, 2021 at 10:30
  • When your field contains delimiter - field in CSV file should be "qualified", basically wrapped in quotas - kb.blackbaud.com/knowledgebase/Article/75155 . It seems like for qualification in your csv '[' and ']' characters are used. CsvHelper libarary does allow you to set qualifier - look for Configuration.Quote field (by default it is double quotas) Commented Mar 5, 2021 at 10:34
  • i have updated the question with sample value when it fails Commented Mar 5, 2021 at 10:44
  • [ and ] are allowed inside the value? If so, how do you escape them to differentiate from the ones used for field quotation? Commented Mar 5, 2021 at 11:03
  • thats what i am unable to do it..this is where i fail Commented Mar 5, 2021 at 12:21

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.