csv.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #include "pocketpy/csv.h"
  2. namespace pkpy{
  3. void add_module_csv(VM *vm){
  4. PyVar mod = vm->new_module("csv");
  5. vm->bind(mod, "reader(csvfile: list[str]) -> list[list]", [](VM* vm, ArgsView args){
  6. const List& csvfile = CAST(List&, args[0]);
  7. List ret;
  8. for(int i=0; i<csvfile.size(); i++){
  9. std::string_view line = CAST(Str&, csvfile[i]).sv();
  10. if(i == 0){
  11. // Skip utf8 BOM if there is any.
  12. if (strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3);
  13. }
  14. List row;
  15. int j;
  16. bool in_quote = false;
  17. std::string buffer;
  18. __NEXT_LINE:
  19. j = 0;
  20. while(j < line.size()){
  21. switch(line[j]){
  22. case '"':
  23. if(in_quote){
  24. if(j+1 < line.size() && line[j+1] == '"'){
  25. buffer += '"';
  26. j++;
  27. }else{
  28. in_quote = false;
  29. }
  30. }else{
  31. in_quote = true;
  32. }
  33. break;
  34. case ',':
  35. if(in_quote){
  36. buffer += line[j];
  37. }else{
  38. row.push_back(VAR(buffer));
  39. buffer.clear();
  40. }
  41. break;
  42. case '\r':
  43. break; // ignore
  44. default:
  45. buffer += line[j];
  46. break;
  47. }
  48. j++;
  49. }
  50. if(in_quote){
  51. if(i == csvfile.size()-1){
  52. vm->ValueError("unterminated quote");
  53. }else{
  54. buffer += '\n';
  55. i++;
  56. line = CAST(Str&, csvfile[i]).sv();
  57. goto __NEXT_LINE;
  58. }
  59. }
  60. row.push_back(VAR(buffer));
  61. ret.push_back(VAR(std::move(row)));
  62. }
  63. return VAR(std::move(ret));
  64. });
  65. vm->bind(mod, "DictReader(csvfile: list[str]) -> list[dict]", [](VM* vm, ArgsView args){
  66. PyVar csv_reader = vm->_modules["csv"]->attr("reader");
  67. PyVar ret_obj = vm->call(csv_reader, args[0]);
  68. const List& ret = CAST(List&, ret_obj);
  69. if(ret.size() == 0){
  70. vm->ValueError("empty csvfile");
  71. }
  72. List header = CAST(List&, ret[0]);
  73. List new_ret;
  74. for(int i=1; i<ret.size(); i++){
  75. const List& row = CAST(List&, ret[i]);
  76. if(row.size() != header.size()){
  77. vm->ValueError("row.size() != header.size()");
  78. }
  79. Dict row_dict;
  80. for(int j=0; j<header.size(); j++){
  81. row_dict.set(vm, header[j], row[j]);
  82. }
  83. new_ret.push_back(VAR(std::move(row_dict)));
  84. }
  85. return VAR(std::move(new_ret));
  86. });
  87. }
  88. } // namespace pkpy