Search code examples
c#csvvisual-c++csvhelper

How can I use CsvHelper to parse a string into a list of tokens?


I have a C# DLL which already uses CsvHelper to read CSV files. So I was wondering if CsvHelper has the capacity for me to simply pass it a string (not a file) and it return the list of tokens?

So much so, that:

2023/11/06,Name,PartType,"“Hey, This is the Theme!”",1

becomes a list:

  1. 2023/11/06
  2. Name
  3. PartType
  4. “Hey, This is the Theme!”
  5. 1

Update

I have ended up with this C# method, based on some other answers and the comments below:

public int ParseCSVText(string textToParse, string delimiter, out string[] tokens)
{
    List<string> listTokens = new List<string>();
    using (var stringReader = new StreamReader(textToParse))
    {
        var config = new CsvConfiguration(CultureInfo.InvariantCulture);
        config.Delimiter = delimiter;
        config.HasHeaderRecord = false;

        using (var reader = new CsvReader(stringReader, config))
        {
            while (reader.Read())
            {
                listTokens.Add(reader.GetField(0));
                listTokens.Add(reader.GetField(1));
                listTokens.Add(reader.GetField(2));
                listTokens.Add(reader.GetField(3));
                listTokens.Add(reader.GetField(4));
            }
        }
    }

    tokens = listTokens.ToArray();

    return listTokens.Count;
}

The associated C++ wrapper:

bool CMSATools::ParseCSVText(const int fieldCount, const CString textToParse, const CString delimiter, CStringArray& listTokens)
{
    SAFEARRAY* saTokens = nullptr;

    if (m_pInterface != nullptr)
    {
        long count{};
        const auto hr = m_pInterface->ParseCSVText(textToParse.AllocSysString(), delimiter.AllocSysString(), &saTokens, &count);
        if (SUCCEEDED(hr))
            ConvertSAFEARRAY<BSTR, CStringArray>(saTokens, listTokens);
        else
            throw_if_fail(hr);
    }

    return listTokens.GetSize() == fieldCount;
}

But when I run my code, eg:

theApp.MSAToolsInterface().ParseCSVText(5, lineText, strDelimiter, listFields)

and go into debug the HRESULT of the C# is saying the file can't be found. There is no file - it is a string. 🧐


Solution

  • Here is the final method:

    public int ParseCSVText(string textToParse, string delimiter, out string[] tokens)
    {
        List<string> listTokens = new List<string>();
        try
        {
           using (var stringReader = new StringReader(textToParse))
           {
               var config = new CsvConfiguration(CultureInfo.InvariantCulture);
               config.Delimiter = delimiter;
               config.HasHeaderRecord = false;
    
               using (var reader = new CsvReader(stringReader, config))
               {
                   while (reader.Read())
                   {
                       for (int column = 0; column < reader.ColumnCount; column++)
                       {
                           listTokens.Add(reader.GetField(column));
                       }
                   }
               }
           }
        }
        catch (Exception ex)
        {
           SimpleLog.Log(ex);
        }
    
        tokens = listTokens.ToArray();
    
        return listTokens.Count;
    }