Skip to content

Instantly share code, notes, and snippets.

@kennyalive
Created September 21, 2019 22:08
Show Gist options
  • Select an option

  • Save kennyalive/cd222b50e17fd06aaf7e8d11ab01f261 to your computer and use it in GitHub Desktop.

Select an option

Save kennyalive/cd222b50e17fd06aaf7e8d11ab01f261 to your computer and use it in GitHub Desktop.
Text file parsing.
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