#include <iostream>
#include <map>
#include <string>
#include <boost/xpressive/xpressive.hpp>
bool FindVariableString(
const std::string &str,
const std::string::size_type pos,
std::string::size_type &beginVarStringPos,
std::string::size_type &endVarStringPos,
std::string::size_type &beginVarNamePos,
std::string::size_type &endVarNamePos)
{
const char *TestString = "%$#";
const char PercentSign = '%';
const char LeftParenthesis = '(';
const char LeftSquareBracket = '[';
const char LeftCurlyBracket = '{';
const char RightParenthesis = ')';
const char RightSquareBracket = ']';
const char RightCurlyBracket = '}';
beginVarStringPos = std::string::npos;
endVarStringPos = std::string::npos;
beginVarNamePos = std::string::npos;
endVarNamePos = std::string::npos;
if (str.empty())
{
return false;
}
beginVarStringPos = str.find_first_of(TestString, pos);
if (std::string::npos == beginVarStringPos)
{
return false;
}
if (beginVarStringPos >= str.length() - 1)
{
return false;
}
char ch = str[beginVarStringPos];
char ch1 = str[beginVarStringPos + 1];
if (
PercentSign == ch
&& LeftParenthesis != ch1 && LeftSquareBracket != ch1
&& LeftCurlyBracket != ch1
)
{
beginVarNamePos = beginVarStringPos + 1;
endVarStringPos = str.find(PercentSign, beginVarNamePos);
if (std::string::npos == endVarStringPos)
{
return false;
}
}
else if (
LeftParenthesis != ch1 && LeftSquareBracket != ch1
&& LeftCurlyBracket != ch1
)
{
return false;
}
else
{
beginVarNamePos = beginVarStringPos + 2;
char closeChar = 0;
if (LeftParenthesis == ch1)
{
closeChar = RightParenthesis;
}
else if (LeftSquareBracket == ch1)
{
closeChar = RightSquareBracket;
}
else if (LeftCurlyBracket == ch1)
{
closeChar = RightCurlyBracket;
}
endVarStringPos = str.find(closeChar, beginVarNamePos);
if (std::string::npos == endVarStringPos)
{
return false;
}
}
endVarNamePos = endVarStringPos - 1;
return true;
}
bool StringContainsVariableStrings(const std::string &str)
{
std::string::size_type beginVarStringPos = 0;
std::string::size_type endVarStringPos = 0;
std::string::size_type beginVarNamePos = 0;
std::string::size_type endVarNamePos = 0;
bool ret = FindVariableString(str, 0, beginVarStringPos, endVarStringPos, beginVarNamePos, endVarNamePos);
return ret;
}
std::string GetVariableValue(
const std::string &varName,
const std::map<std::string, std::string> &env,
bool &fromEnvMap, bool &valueContainsVariableStrings)
{
typedef std::map<std::string, std::string> my_map;
fromEnvMap = false;
valueContainsVariableStrings = false;
std::string ret;
my_map::const_iterator itFind = env.find(varName);
if (itFind != env.end())
{
ret = (*itFind).second;
if (!ret.empty())
{
fromEnvMap = true;
valueContainsVariableStrings = StringContainsVariableStrings(ret);
}
}
if (ret.empty())
{
ret = ::getenv(varName.c_str());
}
return ret;
}
::boost::xpressive::sregex GetRegex()
{
namespace xpr = ::boost::xpressive;
xpr::sregex ret =
"%" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '%'
| "%(" >> (xpr::s1 = +(xpr::_w | xpr::_s)) >> ')'
| "%[" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> ']'
| "%{" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '}'
| "$(" >> (xpr::s1 = +(xpr::_w | xpr::_s)) >> ')'
| "$[" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> ']'
| "${" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '}'
| "#(" >> (xpr::s1 = +(xpr::_w | xpr::_s)) >> ')'
| "#[" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> ']'
| "#{" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '}';
return ret;
}
struct string_formatter
{
typedef std::map<std::string, std::string> env_map;
env_map env;
mutable bool valueContainsVariables;
string_formatter()
{
valueContainsVariables = false;
}
template<typename Out>
Out operator()(::boost::xpressive::smatch const& what, Out out) const
{
bool fromEnvMap;
bool valueContainsVariableStrings;
std::string value = GetVariableValue(
what.str(1), env, fromEnvMap, valueContainsVariableStrings);
if (fromEnvMap && !value.empty() && valueContainsVariableStrings)
{
valueContainsVariables = true;
}
if (value.empty())
{
value = what[0];
}
if (!value.empty())
{
out = std::copy(value.begin(), value.end(), out);
}
return out;
}
};
std::string ExpandVarsR(
const std::string &original,
const std::map<std::string, std::string> &env)
{
std::string ret = original;
if (original.empty())
{
return ret;
}
string_formatter fmt;
fmt.env = env;
fmt.valueContainsVariables = false;
::boost::xpressive::sregex envar = GetRegex();
ret = ::boost::xpressive::regex_replace(original, envar, fmt);
if (fmt.valueContainsVariables)
{
std::string newValue;
std::string prevValue = ret;
do
{
fmt.valueContainsVariables = false;
newValue = ::boost::xpressive::regex_replace(prevValue, envar, fmt);
if (0 == prevValue.compare(newValue))
{
break;
}
prevValue.erase();
prevValue = newValue;
}
while (fmt.valueContainsVariables);
if (0 != ret.compare(newValue))
{
ret = newValue;
}
}
return ret;
}
std::string GetDateFormatStringExpandVars(const std::string& langCode)
{
if (
0 == langCode.compare(0, 2, "en")
|| 0 == langCode.compare(0, 2, "EN")
)
{
return std::string("${month}/${day}/${year}");
}
else if (
0 == langCode.compare(0, 2, "fr")
|| 0 == langCode.compare(0, 2, "FR")
)
{
return std::string("${day}/${month}/${year}");
}
else if (
0 == langCode.compare(0, 2, "ja")
|| 0 == langCode.compare(0, 2, "JA")
|| 0 == langCode.compare(0, 2, "jp")
|| 0 == langCode.compare(0, 2, "JP")
)
{
return std::string("${year}/${day}/${month}");
}
return std::string("${month}/${day}/${year}");
}
std::string GetDateStringExpandVarsR(
const std::string &langCode, int month, int day, int year)
{
std::string fmt = GetDateFormatStringExpandVars(langCode);
std::map<std::string,std::string> env{
{"month", std::to_string(month)},
{"day", std::to_string(day)},
{"year", std::to_string(year)}
};
std::string ret = ExpandVarsR(fmt, env);
return ret;
}
int main()
{
std::cout << GetDateStringExpandVarsR("en", 11, 7, 2018) << "\n";
return 0;
}