I am trying to create a version of the string literal form JavaScript in C++ (combined with colors and formatting options. I would like to create an error message if a closing brace for a tag is not found (example(s) below).
However, I cannot seem to figure out how to display an error message (whether be that stderr or cout) correctly.
What it is supposed to do is fairly simple: if there is a missing ‘}’, then it will simply say "Missing closing '}' from:nc_RED"
If there are multiple missing braces (Example: print("c_RED{f_BOLD{HI!);
) it would print
"Missing closing '}' from:nc_REDnf_BOLD
And a final example: print("c_RED{f_BOLD{HI!}");
would print "Missing closing '}' from:nc_RED
Question: How can I create error handling for missing closing braces?
main.cpp:
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <regex>
#include <iomanip>
#include <stack>
std::map<std::string, std::string> color_map = {
//This is a pretty long array
//It just contains a bunch of colors and ANSI equivalences
{"c_RED", "33[31m"} //Simple example
};
// Map of formatting functions
std::map<std::string, std::string> format_map = {
{"f_BOLD", "33[1m"},
{"f_UNDERLINE", "33[4m"},
{"f_ITALICS", "33[3m"}
};
// Utility function to convert any type to a string
template <typename T>
std::string to_string(const T& value) {
std::ostringstream oss;
oss << value;
return oss.str();
}
// Function to process and replace placeholders in the format string
std::string process_placeholders(const std::string& format, const std::map<std::string, std::string>& values) {
std::string result = format;
// Replace "->" with newline character "n"
size_t pos = result.find("->");
while (pos != std::string::npos) {
result.replace(pos, 2, "n");
pos = result.find("->", pos + 1);
}
// Regular expression to match ${...} placeholders
std::regex placeholder("\$\{(\w+)\}");
std::smatch match;
while (std::regex_search(result, match, placeholder)) {
std::string key = match[1].str();
auto it = values.find(key);
if (it != values.end()) {
result.replace(match.position(0), match.length(0), it->second);
} else {
result.replace(match.position(0), match.length(0), "--Naming Error--");
}
}
return result;
}
// Helper function to capture variables and their values
std::map<std::string, std::string> capture_vars(const std::initializer_list<std::pair<const std::string, std::string>>& pairs) {
return std::map<std::string, std::string>(pairs);
}
// Function to convert hex color code to ANSI escape sequence
std::string hex_to_ansi(const std::string& hex_color) {
auto it = color_map.find(hex_color);
if (it != color_map.end()) {
return it->second;
} else {
// Default to white if color not found
return color_map["c_WHITE"];
}
}
// Function to apply color and formatting tags to a string
std::string apply_tags(const std::string& input) {
std::string result = input;
// Regex to match color and formatting tags in the format string
std::regex tag_regex("(c_\w+|f_\w+)\{([^\}]+)\}");
std::smatch match;
// Replace tags with ANSI escape sequences
while (std::regex_search(result, match, tag_regex)) {
std::string full_match = match[0].str();
std::string tag_type = match[1].str();
std::string content = match[2].str();
std::string prefix, suffix = "33[0m";
if (tag_type[0] == 'c') {
// Color tag found, replace with ANSI escape sequence for color
prefix = hex_to_ansi(tag_type);
} else if (tag_type[0] == 'f') {
// Formatting tag found, replace with ANSI escape sequence for formatting
prefix = format_map[tag_type];
}
// Recursive call to handle nested tags
content = apply_tags(content);
result.replace(result.find(full_match), full_match.length(), prefix + content + suffix);
}
return result;
}
// Print function that uses the map and placeholder processing function
void print(const std::string& format, const std::map<std::string, std::string>& values) {
std::string result = process_placeholders(format, values);
result = apply_tags(result); // Apply color and formatting tags before printing
std::cout << result << std::endl;
}
int main() {
std::string name;
unsigned int age;
double height;
std::cout << "Enter your name: ";
std::cin >> name;
std::cout << "Enter your age: ";
std::cin >> age;
std::cout << "Enter your height: ";
std::cin >> height;
// Capture local variables and their values
auto values = capture_vars({
{"name", to_string(name)},
{"age", to_string(age)},
{"height", to_string(height)}
});
// Print the formatted string with color and formatting tags
print("f_ITALICS{c_TAN{Hello ${name}}}, c_PINK{f_BOLD{you are ${age} f_UNDERLINE{years old and}}} c_GOLD{${height} feet} c_COPPER{tall?}->c_CYAN{Weird}", values); //This print has all proper syntax and closing braces
return 0;
}
I tried BSing it and winging it and I sort of got it to work to a point where it would display all of the missing braces correctly (example below) but it was off. I want the closing braces to work inside out, so if I have {{EXAMPLE}, then EXAMPLE has the close, but the outside does not. This was not the case.