Vince's CSV Parser
Loading...
Searching...
No Matches
csv_format.cpp
Go to the documentation of this file.
1
5#include <algorithm>
6#include <set>
7
8#include "csv_format.hpp"
9
10namespace csv {
11 namespace internals {
12 char resolved_delimiter(const CSVFormat& format) noexcept {
13 CSV_DEBUG_ASSERT(format.possible_delimiters.size() == 1);
14 return format.possible_delimiters.front();
15 }
16 }
17
18#if CSV_EXCEPTIONS_ENABLED
20 CSVError error;
21 this->try_delimiter(delim, error);
22 internals::throw_error(error);
23 return *this;
24 }
25
26 CSVFormat& CSVFormat::delimiter(const std::vector<char>& delims) {
27 CSVError error;
28 this->try_delimiter(delims, error);
29 internals::throw_error(error);
30 return *this;
31 }
32
34 CSVError error;
35 this->try_quote(quote, error);
36 internals::throw_error(error);
37 return *this;
38 }
39
40 CSVFormat& CSVFormat::trim(const std::vector<char>& whitespace) {
41 CSVError error;
42 this->try_trim(whitespace, error);
43 internals::throw_error(error);
44 return *this;
45 }
46#endif
47
48#if CSV_EXCEPTIONS_ENABLED
49 char CSVFormat::get_delim() const {
50 CSVError error;
51 char value = 0;
52 this->try_get_delim(value, error);
53 internals::throw_error(error);
54 return value;
55 }
56#endif
57
58 bool CSVFormat::try_delimiter(char delim, CSVError& error) {
59 return this->try_delimiter(std::vector<char>{delim}, error);
60 }
61
62 bool CSVFormat::try_delimiter(const std::vector<char>& delims, CSVError& error) {
63 if (!validate_characters(delims, this->trim_chars, this->quote_char, error)) return false;
64 this->possible_delimiters = delims;
65 return true;
66 }
67
68 bool CSVFormat::try_quote(char quote, CSVError& error) {
69 if (!validate_characters(this->possible_delimiters, this->trim_chars, quote, error)) return false;
70 this->no_quote = false;
71 this->quote_char = quote;
72 return true;
73 }
74
75 bool CSVFormat::try_trim(const std::vector<char>& whitespace, CSVError& error) {
76 if (!validate_characters(this->possible_delimiters, whitespace, this->quote_char, error)) return false;
77 this->trim_chars = whitespace;
78 return true;
79 }
80
81 bool CSVFormat::try_get_delim(char& out, CSVError& error) const {
82 error.clear();
83 if (this->possible_delimiters.size() != 1) {
84 return internals::fail_static(error, CSVErrorCode::InvalidFormat,
85 this->possible_delimiters.empty() ? "At least one delimiter is required."
86 : internals::ERROR_MULTIPLE_DELIMITERS);
87 }
88 out = this->possible_delimiters.front();
89 return true;
90 }
91
92 CSVFormat& CSVFormat::column_names(const std::vector<std::string>& names) {
93 this->col_names = names;
94 this->header = -1;
95 this->col_names_explicitly_set_ = true;
96 return *this;
97 }
98
100 if (row < 0) this->variable_column_policy = VariableColumnPolicy::KEEP;
101
102 this->header = row;
103 this->header_explicitly_set_ = true;
104 this->col_names = {};
105 this->col_names_explicitly_set_ = false;
106 return *this;
107 }
108
109#if CSV_EXCEPTIONS_ENABLED
111 CSVError error;
112 this->try_chunk_size(size, error);
113 internals::throw_error(error);
114 return *this;
115 }
116#endif
117
118 bool CSVFormat::try_chunk_size(size_t size, CSVError& error) {
119 error.clear();
120 if (size < internals::CSV_CHUNK_SIZE_FLOOR) {
121 return internals::fail(error, CSVErrorCode::InvalidChunkSize,
122 internals::make_chunk_size_error(internals::CSV_CHUNK_SIZE_FLOOR, size));
123 }
124 const size_t max_chunk_size = internals::CSV_CHUNK_SIZE_MAX;
125 if (size > max_chunk_size) {
126 return internals::fail(error, CSVErrorCode::InvalidChunkSize,
127 internals::make_chunk_size_ceiling_error(max_chunk_size, size));
128 }
129 this->_chunk_size = size;
130 return true;
131 }
132
133 bool CSVFormat::validate_characters(
134 const std::vector<char>& candidates, const std::vector<char>& whitespace,
135 char quote, CSVError& error
136 ) {
137 error.clear();
138 if (candidates.empty()) {
139 return internals::fail_static(error, CSVErrorCode::InvalidFormat, "At least one delimiter is required.");
140 }
141 const std::set<char> delims(candidates.begin(), candidates.end());
142 const std::set<char> trims(whitespace.begin(), whitespace.end());
143 std::set<char> offenders;
144
145 for (std::set<char>::const_iterator it = delims.begin(); it != delims.end(); ++it) {
146 if (trims.find(*it) != trims.end()) offenders.insert(*it);
147 }
148
149 // Make sure quote character is not contained in possible delimiters
150 // or whitespace characters.
151 if (delims.find(quote) != delims.end() || trims.find(quote) != trims.end()) {
152 offenders.insert(quote);
153 }
154 if (!offenders.empty()) {
155 return internals::fail(error, CSVErrorCode::InvalidFormat, internals::make_char_overlap_error(offenders));
156 }
157 return true;
158 }
160 CSVFormat format;
161 format.possible_delimiters = { ',', '|', '\t', ';', '^' };
162 // Assign header directly rather than via header_row() so that
163 // header_explicitly_set_ remains false — the guesser must be free
164 // to detect the real header row at construction time.
165 format.header = 0;
166
167 return format;
168 }
169
170}
Stores information about how to parse a CSV file.
CSVFormat & column_names(const std::vector< std::string > &names)
Sets the column names.
CSVFormat & chunk_size(size_t size)
Sets the chunk size used when reading the CSV.
static CSVFormat guess_csv()
CSVFormat preset for delimiter inference with header/n_cols inference enabled.
CSVFormat & trim(const std::vector< char > &ws)
Sets the whitespace characters to be trimmed.
CSVFormat & delimiter(char delim)
Sets the delimiter of the CSV file.
bool try_get_delim(char &out, CSVError &error) const
Retrieve a resolved delimiter; unresolved candidate lists report InvalidFormat.
bool try_delimiter(char delim, CSVError &error)
Set parsing characters, returning false and preserving the format on invalid input.
CSVFormat & header_row(int row)
Sets the header row.
CSVFormat & quote(char quote)
Sets the quote character.
bool try_chunk_size(size_t size, CSVError &error)
Set a valid chunk size, preserving the previous value on failure.
char resolved_delimiter(const CSVFormat &format) noexcept
Read a delimiter after configuration has been validated and resolved to one candidate.
Defines an object used to store CSV format settings.
The all encompassing namespace.
@ InvalidFormat
Conflicting parsing characters or an unresolved delimiter query.
@ InvalidChunkSize
Configured read-window size is outside the supported byte limits.
A diagnostic whose text remains valid for the lifetime of the error.
Definition csv_error.hpp:94