Last active
October 12, 2020 05:26
-
-
Save ugovaretto/826c04b4a8d3f0b617dcf77cf6f1ddb1 to your computer and use it in GitHub Desktop.
Parse TOML files using only C++ standard regex module
This file contains 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
// Parse TOML file with standard regex module, no validation | |
// Author: Ugo Varetto | |
#include <fstream> | |
#include <iostream> | |
#include <regex> | |
#include <string> | |
#include <unordered_map> | |
using namespace std; | |
using Dict = unordered_map<std::string, std::string>; | |
using Toml = unordered_map<std::string, Dict>; | |
namespace { | |
void Trim(string& s) { | |
auto i = s.find("#"); | |
if (i != string::npos) s.erase(i); | |
i = s.find_last_not_of(" \r\n\t"); | |
if(i != string::npos) s.erase(++i); | |
} | |
} // namespace | |
Toml ParseTomlFile(const string& filename) { | |
ifstream is(filename); | |
if (!is) { | |
throw std::invalid_argument("Cannot open file " + filename); | |
return {}; | |
} | |
string line; | |
const string section = "^\\s*\\[\\s*([^\\]]+)\\]\\s*$"; | |
int lineCount = 0; | |
string curSection; | |
Toml toml; | |
Dict curSectionData; | |
string lastKey; | |
while (getline(is, line)) { | |
++lineCount; | |
if (line.size() == 0 || regex_search(line, regex{"^\\s*#"})) { | |
continue; | |
} | |
smatch sm; | |
if (regex_search(line, sm, regex{section})) { | |
if (curSection.size() != 0) { | |
toml[curSection] = curSectionData; | |
curSectionData.clear(); | |
lastKey.clear(); | |
} | |
curSection = sm[1]; | |
} else { | |
smatch sm; | |
if (regex_search(line, sm, regex{"\\s*(\\w+)\\s*=\\s*(.*)"})) { | |
string value = sm[2]; | |
Trim(value); | |
curSectionData[sm[1]] = value; | |
lastKey = sm[1]; | |
} else { | |
if (lastKey.empty()) { | |
throw std::runtime_error("Toml parsing error, line " + | |
to_string(lineCount)); | |
} | |
if (line.size() == 0) continue; | |
Trim(line); | |
curSectionData[lastKey] += line; | |
} | |
} | |
} | |
if (toml.find(curSection) == toml.end()) { | |
toml[curSection] = curSectionData; | |
} | |
return toml; | |
} | |
int main(int argc, char const* argv[]) { | |
if (argc != 2) { | |
cerr << "usage: " << argv[0] << " toml filename" << endl; | |
return 1; | |
} | |
auto toml = ParseTomlFile(argv[1]); | |
for (auto kv : toml) { | |
cout << "[" << kv.first << "]" << endl; | |
for (auto i : kv.second) { | |
cout << "\t" << i.first << ": " << i.second << endl; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment