79240690

Date: 2024-12-01 00:12:48
Score: 1
Natty:
Report link

I have expanded on @Joel's answer above following the comments as what he produced seemed the closest I had found to dealing with a CSV where the data also contains commas so simply doing a split on the string does not work as splits on commas in fields too: https://stackoverflow.com/a/63202295/915426

This version uses string builder for increased performance and also adds a new line character to the end of the string if it does not end with one to ensure the last line of data gets included but is otherwise the same:

static List<List<string>> ParseCsv(string csv)
{
    var parsedCsv = new List<List<string>>();
    var row = new List<string>();
    StringBuilder field = new StringBuilder();
    bool inQuotedField = false;

    //If CSV does not end with a new line character then add one to ensure final line of data is included
    if (csv.Substring(csv.Length - 1, 1) != "\n")
    {
        csv = csv += "\n";
    }

    for (int i = 0; i < csv.Length; i++)
    {
        char current = csv[i];
        char next = i == csv.Length - 1 ? ' ' : csv[i + 1];

        // if current character is not a quote or comma or carriage return or newline (or not a quote and currently in an a quoted field), just add the character to the current field text
        if ((current != '"' && current != ',' && current != '\r' && current != '\n') || (current != '"' && inQuotedField))
        {
            field.Append(current);
        }
        else if (current == ' ' || current == '\t')
        {
            continue; // ignore whitespace outside a quoted field
        }
        else if (current == '"')
        {
            if (inQuotedField && next == '"')
            { // quote is escaping a quote within a quoted field
                i++; // skip escaping quote
                field.Append(current);
            }
            else if (inQuotedField)
            { // quote signifies the end of a quoted field
                row.Add(field.ToString());
                if (next == ',')
                {
                    i++; // skip the comma separator since we've already found the end of the field
                }
                field = new StringBuilder(); //Clear value
                inQuotedField = false;
            }
            else
            { // quote signifies the beginning of a quoted field
                inQuotedField = true;
            }
        }
        else if (current == ',')
        { //
            row.Add(field.ToString());
            field = new StringBuilder(); //Clear value
        }
        else if (current == '\n')
        {
            row.Add(field.ToString());
            parsedCsv.Add(new List<string>(row));
            field = new StringBuilder(); //Clear value
            row.Clear();
        }
    }

    return parsedCsv;
}
Reasons:
  • Blacklisted phrase (1): stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @Joel's
  • Low reputation (0.5):
Posted by: Robin Wilson