| 487 | } // namespace |
| 488 | |
| 489 | void ParseCSVRow(std::string const & row, char const delimiter, std::vector<std::string> & target) |
| 490 | { |
| 491 | target.clear(); |
| 492 | |
| 493 | std::string prevColumns; |
| 494 | for (TokenizeIterator<SimpleDelimiter, std::string::const_iterator, true /* KeepEmptyTokens */> it{ |
| 495 | row.begin(), row.end(), delimiter}; |
| 496 | it; ++it) |
| 497 | { |
| 498 | std::string_view column = *it; |
| 499 | size_t const quotesCount = std::count(column.begin(), column.end(), '"'); |
| 500 | bool const evenQuotes = quotesCount % 2 == 0; |
| 501 | if (prevColumns.empty()) |
| 502 | { |
| 503 | if (evenQuotes) |
| 504 | { |
| 505 | if (quotesCount == 0) |
| 506 | target.emplace_back(column); |
| 507 | else |
| 508 | { |
| 509 | std::string strColumn{column}; |
| 510 | target.push_back(UnescapeCSVColumn(strColumn)); |
| 511 | } |
| 512 | } |
| 513 | else |
| 514 | { |
| 515 | prevColumns = column; |
| 516 | prevColumns.push_back(','); |
| 517 | } |
| 518 | } |
| 519 | else |
| 520 | { |
| 521 | prevColumns.append(column); |
| 522 | if (evenQuotes) |
| 523 | prevColumns.push_back(','); |
| 524 | else |
| 525 | { |
| 526 | target.push_back(UnescapeCSVColumn(prevColumns)); |
| 527 | prevColumns.clear(); |
| 528 | } |
| 529 | } |
| 530 | } |
| 531 | |
| 532 | // Special case: if the string is empty, return an empty array instead of {""}. |
| 533 | if (target.size() == 1 && target[0].empty()) |
| 534 | target.clear(); |
| 535 | } |
| 536 | |
| 537 | } // namespace strings |