Created
September 21, 2019 22:08
-
-
Save kennyalive/cd222b50e17fd06aaf7e8d11ab01f261 to your computer and use it in GitHub Desktop.
Text file parsing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct Text_File_Lines { | |
| std::string text; | |
| std::vector<size_t> line_start_positions; // the last element is a position at the end of the file | |
| }; | |
| struct Text_File_Parser { | |
| private: | |
| size_t pos = 0; | |
| int line = -1; | |
| Text_File_Lines* text_file = nullptr; | |
| public: | |
| Text_File_Parser(Text_File_Lines* text_file) : text_file(text_file) {} | |
| std::string_view next_token() { | |
| bool new_line = false; | |
| bool start_found = false; | |
| size_t start; | |
| for (; pos < text_file->text.size(); pos++) { | |
| // Check for new line. | |
| if (pos == text_file->line_start_positions[line + 1]) { | |
| line++; | |
| new_line = true; | |
| } | |
| // Process next character. | |
| if (text_file->text[pos] <= 32) { // whitespace is found | |
| if (start_found) { | |
| start_found = false; | |
| size_t length = pos - start; | |
| pos++; | |
| return std::string_view(text_file->text.c_str() + start, length); | |
| } | |
| } else { // not-whitespace character | |
| if (!start_found) { | |
| if (new_line && text_file->text[pos] == '#') { | |
| pos = text_file->line_start_positions[line + 1] - 1 /*take into account increment in for loop*/; | |
| line++; | |
| } else { | |
| start = pos; | |
| start_found = true; | |
| } | |
| } | |
| } | |
| } | |
| // the last token in the file | |
| if (start_found) { | |
| return std::string_view(text_file->text.c_str() + start, text_file->text.length() - start); | |
| } else | |
| return std::string_view(); // signal end of stream | |
| } | |
| bool parse_integers(int* values, int count) { | |
| for (int i = 0; i < count; i++) { | |
| std::string_view token = next_token(); | |
| if (!parse_int(token, &values[i])) | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool parse_floats(float* values, int count) { | |
| for (int i = 0; i < count; i++) { | |
| std::string_view token = next_token(); | |
| if (!parse_float(token, &values[i])) | |
| return false; | |
| } | |
| return true; | |
| } | |
| private: | |
| bool parse_int(const std::string_view& token, int* value) { | |
| std::from_chars_result result = std::from_chars(token.data(), token.data() + token.length(), *value); | |
| return result.ptr == token.data() + token.length(); | |
| } | |
| bool parse_float(const std::string_view& token, float* value) { | |
| std::from_chars_result result = std::from_chars(token.data(), token.data() + token.length(), *value); | |
| return result.ptr == token.data() + token.length(); | |
| } | |
| }; | |
| // Prepares Text_File_Lines sructure. Just an example, it's not an efficient implementation. | |
| Text_File_Lines read_text_file_by_lines(const std::string& file_name) { | |
| std::string abs_path = get_resource_path(file_name); | |
| std::ifstream file(abs_path); | |
| if (!file) | |
| error("failed to open file: %s", abs_path.c_str()); | |
| Text_File_Lines result; | |
| result.line_start_positions.push_back(0); | |
| std::stringstream ss; | |
| for (std::string line; std::getline(file, line); ) { | |
| ss << line << "\n"; | |
| result.line_start_positions.push_back(result.line_start_positions.back() + line.length() + 1 /*new line*/); | |
| } | |
| result.text = ss.str(); | |
| return result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment