GnuCash c935c2f+
Loading...
Searching...
No Matches
Public Member Functions
GncCsvTokenizer Class Reference
Inheritance diagram for GncCsvTokenizer:
GncTokenizer

Public Member Functions

 GncCsvTokenizer (const GncCsvTokenizer &)=default
 
GncCsvTokenizeroperator= (const GncCsvTokenizer &)=default
 
 GncCsvTokenizer (GncCsvTokenizer &&)=default
 
GncCsvTokenizeroperator= (GncCsvTokenizer &&)=default
 
void set_separators (const std::string &separators)
 
void set_enable_escape (const bool enable)
 
int tokenize () override
 
- Public Member Functions inherited from GncTokenizer
 GncTokenizer (const GncTokenizer &)=default
 
GncTokenizeroperator= (const GncTokenizer &)=default
 
 GncTokenizer (GncTokenizer &&)=default
 
GncTokenizeroperator= (GncTokenizer &&)=default
 
virtual void load_file (const std::string &path)
 
const std::string & current_file ()
 
void encoding (const std::string &encoding)
 
const std::string & encoding ()
 
const std::vector< StrVec > & get_tokens ()
 

Additional Inherited Members

- Protected Attributes inherited from GncTokenizer
std::string m_utf8_contents
 
std::vector< StrVec > m_tokenized_contents
 

Detailed Description

Definition at line 45 of file gnc-tokenizer-csv.hpp.

Member Function Documentation

◆ set_enable_escape()

void GncCsvTokenizer::set_enable_escape ( const bool  enable)

Definition at line 47 of file gnc-tokenizer-csv.cpp.

48{
49 m_enable_escape = enable;
50}

◆ set_separators()

void GncCsvTokenizer::set_separators ( const std::string &  separators)

Definition at line 41 of file gnc-tokenizer-csv.cpp.

42{
43 m_sep_str = separators;
44}

◆ tokenize()

int GncCsvTokenizer::tokenize ( )
overridevirtual

Implements GncTokenizer.

Definition at line 53 of file gnc-tokenizer-csv.cpp.

54{
55 using Tokenizer = boost::tokenizer< boost::escaped_list_separator<char>>;
56
57 boost::escaped_list_separator<char> sep("\\", m_sep_str, "\"");
58
59 StrVec vec;
60 std::string line;
61 std::string buffer;
62
63 bool inside_quotes(false);
64 size_t last_quote(0);
65
66 m_tokenized_contents.clear();
67 std::istringstream in_stream(m_utf8_contents);
68
69 try
70 {
71 while (std::getline (in_stream, buffer))
72 {
73 // --- deal with line breaks in quoted strings
74 buffer = boost::trim_copy (buffer); // Removes trailing newline and spaces
75 last_quote = buffer.find_first_of('"');
76 while (last_quote != std::string::npos)
77 {
78 if (last_quote == 0) // Test separately because last_quote - 1 would be out of range
79 inside_quotes = !inside_quotes;
80 else if (!m_enable_escape || buffer[ last_quote - 1 ] != '\\')
81 inside_quotes = !inside_quotes;
82
83 last_quote = buffer.find_first_of('"',last_quote+1);
84 }
85
86 line.append(buffer);
87 if (inside_quotes)
88 {
89 line.append(" ");
90 continue;
91 }
92 // ---
93
94 // Deal with backslashes that are not meant to be escapes
95 // The boost::tokenizer with escaped_list_separator as we use
96 // it would choke on this.
97 auto bs_pos = line.find ('\\');
98 while (bs_pos != std::string::npos)
99 {
100 if (! m_enable_escape)
101 {
102 // Put an escape before this escape and look for the next
103 line.insert (bs_pos, 1, '\\');
104 bs_pos += 2;
105 }
106 else
107 {
108 // Process as before
109 if ((bs_pos == line.size()) || // got trailing single backslash
110 (line.find_first_of ("\"\\n", bs_pos + 1) != bs_pos + 1)) // backslash is not part of known escapes \\, \" or \n
111 line = line.substr(0, bs_pos) + "\\\\" + line.substr(bs_pos + 1);
112 bs_pos += 2;
113 }
114
115 bs_pos = line.find ('\\', bs_pos);
116 }
117
118 // Deal with repeated " ("") in strings.
119 // This is commonly used as escape mechanism for double quotes in csv files.
120 // However boost just eats them.
121 bs_pos = line.find ("\"\"");
122 while (bs_pos != std::string::npos)
123 {
124 // Only make changes in case the double quotes are part of a larger field
125 // In other words a field which only contains two double quotes represent an
126 // empty field. We don't need to touch those.
127 // The way to determine whether the double quotes represent an empty string
128 // is by checking whether the character in front or after are either
129 // a field separator or the beginning or end of of the string.
130 if (!(((bs_pos == 0) || // quotes are at start of line
131 (m_sep_str.find (line[bs_pos-1]) != std::string::npos)) // quotes preceded by field separator
132 &&
133 ((bs_pos + 2 >= line.length()) || // quotes are at end of line
134 (m_sep_str.find (line[bs_pos+2]) != std::string::npos)))) // quotes followed by field separator
135 // Only make changes in case the double quotes are not an empty field
136 line.replace (bs_pos, 2, "\\\"");
137 bs_pos = line.find ("\"\"", bs_pos + 2);
138 }
139
140 Tokenizer tok(line, sep);
141 vec.assign(tok.begin(),tok.end());
142 m_tokenized_contents.push_back(vec);
143 line.clear();
144 }
145 }
146 catch (boost::escaped_list_error &e)
147 {
148 throw (std::range_error N_("There was an error parsing the file."));
149 }
150
151 return 0;
152}

The documentation for this class was generated from the following files: