michalmonday / CSV-Parser-for-Arduino

It turns CSV string into an associative array (like dict in python)
MIT License
57 stars 12 forks source link

Reading multiple files at the same time, row by row #27

Open hapiel opened 7 months ago

hapiel commented 7 months ago

It's currently not easily possible to read multiple files at the same time, when using row by row mode.

Each csv parse instance refers to the same feedRowParser() which then uses the same file:

char feedRowParser() {
  return file.read();
}
bool rowParserFinished() {
  return ((file.available()>0)?false:true);
}

I think it would be better if you can somehow set functions when creating the csv parse instance.

michalmonday commented 7 months ago

That's a good point, I'll add it soon, just need to be careful to avoid breaking the old way.

michalmonday commented 7 months ago

In the 1.4.0 version I added the following 3 methods:

cp.setRowParserFinishedCallback(func_returning_bool);

// only one of these should be used at once:
cp.setFeedRowParserCallback(func_returning_char);
cp.setFeedRowParserStrCallback(func_returning_char_pointer);

// I added "Str" version because it is faster in practice when a whole string is supplied 
// rather than single character. 

Here's a quick example I used to check if it works:


#include <CSV_Parser.h>

char * csv_str = "my_strings,my_numbers\r\n"
                 "hello,5\r\n"
                 "world,10\r\n";
int csv_str_index = 0;

char feedRowParser() {
  return csv_str[csv_str_index++];
}

bool rowParserFinished() {
  return csv_str[csv_str_index] == 0;
}

char * csv_str_2 = "another_strings,another_numbers\r\n"
                 "abcd,1\r\n"
                 "efg,2\r\n\0";
int csv_str_index_2 = 0;

char feedRowParser_2() {
  return csv_str_2[csv_str_index_2++];
}

bool rowParserFinished_2() {
  return csv_str_2[csv_str_index_2] == 0;
}

void setup() {
  Serial.begin(115200);
  delay(5000);

  CSV_Parser cp(/*format*/ "sL");
  cp.setFeedRowParserCallback(feedRowParser);
  cp.setRowParserFinishedCallback(rowParserFinished);

  char **strings = (char**)cp[0];
  int32_t *numbers = (int32_t*)cp[1];

  int row_index = 0;
  while (cp.parseRow()) {    
    char *string = strings[0];
    int32_t number = numbers[0];

    Serial.print(String(row_index) + ". String = ");
    Serial.println(string);
    Serial.print(String(row_index) + ". Number = ");
    Serial.println(number, DEC);
    Serial.println();
    row_index++;
  }

  CSV_Parser cp_2(/*format*/ "sL");
  cp_2.setFeedRowParserCallback(feedRowParser_2);
  cp_2.setRowParserFinishedCallback(rowParserFinished_2);

  char **strings_2 = (char**)cp_2[0];
  int32_t *numbers_2 = (int32_t*)cp_2[1];

  int row_index_2 = 0;
  while (cp_2.parseRow()) {    
    char *string_2 = strings_2[0];
    int32_t number_2 = numbers_2[0];

    Serial.print(String(row_index_2) + ". String = ");
    Serial.println(string_2);
    Serial.print(String(row_index_2) + ". Number = ");
    Serial.println(number_2, DEC);
    Serial.println();
    row_index_2++;
  }  
}

void loop() {

}

And the output was as expected:

0. String = hello
0. Number = 5

1. String = world
1. Number = 10

0. String = abcd
0. Number = 1

1. String = efg
1. Number = 2

New changes should not break any previous codes relying on the "feedRowParser" and "rowParserFinished". I am planning to update examples and README.md but there are few of them so I will add them in new release.

michalmonday commented 7 months ago

I just realized the new change is broken for normal Arduino boards (I tested it only with Esp8266 which has "functional" header file...). I deleted the release to avoid it being pushed to arduino library manager

michalmonday commented 7 months ago

I adapted the code (in version 1.4.1) and now it should be good (hopefully).

hapiel commented 7 months ago

You were so fast with this, thank you!