diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index 3d59e0a..4a1db0f 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -45,7 +45,7 @@ public: if constexpr (ignore_header) { ignore_next(); } else { - header_ = reader_.get_header(); + raw_header_ = reader_.get_buffer(); } } else { handle_error_file_not_open(); @@ -123,6 +123,10 @@ public: } bool field_exists(const std::string& field) { + if (header_.empty()) { + split_header_data(); + } + return header_index(field).has_value(); } @@ -133,6 +137,10 @@ public: return; } + if (header_.empty()) { + split_header_data(); + } + if (!valid()) { return; } @@ -432,6 +440,15 @@ private: // header //////////////// + void split_header_data() { + ss::splitter splitter; + std::string raw_header_copy = raw_header_; + splitter.split(raw_header_copy.data(), reader_.delim_); + for (const auto& [begin, end] : splitter.split_data_) { + header_.emplace_back(begin, end); + } + } + std::optional header_index(const std::string& field) { auto it = std::find(header_.begin(), header_.end(), field); @@ -508,8 +525,7 @@ private: void handle_error_header_ignored() { constexpr static auto error_msg = - ": \"the header row is ignored within the setup it cannot be " - "used\""; + ": the header row is ignored within the setup it cannot be used"; if constexpr (string_error) { error_.clear(); @@ -796,15 +812,8 @@ private: return true; } - std::vector get_header() { - std::vector header; - std::string header_buffer = next_line_buffer_; - ss::splitter splitter; - splitter.split(header_buffer.data(), delim_); - for (const auto& [begin, end] : splitter.split_data_) { - header.emplace_back(begin, end); - } - return header; + std::string get_buffer() { + return std::string{next_line_buffer_}; } //////////////// @@ -838,6 +847,7 @@ private: error_type error_{}; reader reader_; std::vector header_; + std::string raw_header_; bool eof_{false}; }; diff --git a/test/test_parser.cpp b/test/test_parser.cpp index 5b4dfa7..151414c 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -700,7 +700,8 @@ static inline std::string no_quote(const std::string& s) { return s; } -TEST_CASE("parser test csv on multiple lines with quotes") { +template +void test_quote_multiline() { unique_file_name f{"test_parser"}; std::vector data = {{1, 2, "\"x\r\nx\nx\""}, {3, 4, "\"y\ny\r\ny\""}, @@ -720,11 +721,11 @@ TEST_CASE("parser test csv on multiple lines with quotes") { } } - ss::parser> p{f.name, ","}; + ss::parser, Ts...> p{f.name, ","}; std::vector i; while (!p.eof()) { - auto a = p.get_next(); + auto a = p.template get_next(); i.emplace_back(ss::to_object(a)); } @@ -733,13 +734,21 @@ TEST_CASE("parser test csv on multiple lines with quotes") { } CHECK_EQ(i, data); - ss::parser> p_no_multiline{f.name, ","}; + ss::parser, Ts...> p_no_multiline{f.name, ","}; while (!p.eof()) { - auto a = p_no_multiline.get_next(); - CHECK(!p.valid()); + auto command = [&] { + p_no_multiline.template get_next(); + }; + expect_error_on_command(p_no_multiline, command); } } +TEST_CASE("parser test csv on multiple lines with quotes") { + test_quote_multiline(); + test_quote_multiline(); + test_quote_multiline(); +} + static inline std::string no_escape(std::string& s) { s.erase(std::remove(begin(s), end(s), '\\'), end(s)); return s;