Here’s some sample code that expands strings like “$VAR”. There’s a typedef needed and I have it wrapped in a “namespace path” since this code fragment is part of a bigger project. Feel free to use this code however you like.
typedef std::map StringMap
namespace path { /** * Expand any $VAR by looking up VAR in vars and using * the return value. If VAR is not found, then the * empty string is used. VAR can contain letters, digits, and * underscore ('_') (the usual). To escape a dollar sign, use two * dollar signs ('$$'). If you include the variable name in parenthesis, * then any characters are ok: $(A $ %). '[]' and '{}' work * if you need more characters. * * Variables are recursively expanded. So if the expansion includes * a variable, that variable is also expanded. * * @param str The String to be expanded * @param vars A std::map from std::string to std::string * @param tilde True if expand ~ to $HOME (at start) * @return a string with all $VARs expanded. */ std::string expand(const std::string &str, const StringMap &vars, bool tilde) { std::string newstr; const char intro = '$'; const char tilde_char = '~'; for (std::string::const_iterator iter = str.begin(); iter != str.end();) { if (tilde) { tilde = false; // only at the very start if (*iter == tilde_char) { ++iter; newstr += expand("$HOME", vars, false); continue; } } // Search for a '$' if (*iter != intro) { newstr += *iter++; continue; } // We have a '$' std::string var; ++iter; // Treat $$ as an escape for a single '$' if (iter != str.end() && *iter == intro) { newstr += *iter++; continue; } // Get the actual variable bool start = true; bool domatch = false; char match = ')'; // for matching brace/parenthesis while (iter != str.end()) { if (start) { start = false; switch (*iter) { case '(': match = ')'; domatch = true; ++iter; continue; case '{': match = '}'; domatch = true; ++iter; continue; case '[': match = ']'; domatch = true; ++iter; continue; default: break; } } if (domatch) { if (*iter == match) { ++iter; domatch = false; break; } else { var += *iter++; } } else if (isalnum(*iter) || *iter == '_') { var += *iter++; } else { break; } } if (!domatch) { StringMap::const_iterator variter = vars.find(var); // If we added an else, we could have non-matches expand if (variter != vars.end()) newstr += expand(variter->second, vars, false); } } return newstr; } }