fork download
  1. #include <iostream>
  2. #include <map>
  3. #include <string>
  4. #include <boost/xpressive/xpressive.hpp>
  5.  
  6. bool FindVariableString(
  7. const std::string &str,
  8. const std::string::size_type pos,
  9. std::string::size_type &beginVarStringPos,
  10. std::string::size_type &endVarStringPos,
  11. std::string::size_type &beginVarNamePos,
  12. std::string::size_type &endVarNamePos)
  13. {
  14. const char *TestString = "%$#";
  15. const char PercentSign = '%';
  16. const char LeftParenthesis = '(';
  17. const char LeftSquareBracket = '[';
  18. const char LeftCurlyBracket = '{';
  19. const char RightParenthesis = ')';
  20. const char RightSquareBracket = ']';
  21. const char RightCurlyBracket = '}';
  22. beginVarStringPos = std::string::npos;
  23. endVarStringPos = std::string::npos;
  24. beginVarNamePos = std::string::npos;
  25. endVarNamePos = std::string::npos;
  26. if (str.empty())
  27. {
  28. return false;
  29. }
  30. beginVarStringPos = str.find_first_of(TestString, pos);
  31. if (std::string::npos == beginVarStringPos)
  32. {
  33. return false;
  34. }
  35. if (beginVarStringPos >= str.length() - 1)
  36. {
  37. return false;
  38. }
  39. char ch = str[beginVarStringPos];
  40. char ch1 = str[beginVarStringPos + 1];
  41. if (
  42. PercentSign == ch
  43. && LeftParenthesis != ch1 && LeftSquareBracket != ch1
  44. && LeftCurlyBracket != ch1
  45. )
  46. {
  47. beginVarNamePos = beginVarStringPos + 1;
  48. endVarStringPos = str.find(PercentSign, beginVarNamePos);
  49. if (std::string::npos == endVarStringPos)
  50. {
  51. return false;
  52. }
  53. }
  54. else if (
  55. LeftParenthesis != ch1 && LeftSquareBracket != ch1
  56. && LeftCurlyBracket != ch1
  57. )
  58. {
  59. return false;
  60. }
  61. else
  62. {
  63. beginVarNamePos = beginVarStringPos + 2;
  64. char closeChar = 0;
  65. if (LeftParenthesis == ch1)
  66. {
  67. closeChar = RightParenthesis;
  68. }
  69. else if (LeftSquareBracket == ch1)
  70. {
  71. closeChar = RightSquareBracket;
  72. }
  73. else if (LeftCurlyBracket == ch1)
  74. {
  75. closeChar = RightCurlyBracket;
  76. }
  77. endVarStringPos = str.find(closeChar, beginVarNamePos);
  78. if (std::string::npos == endVarStringPos)
  79. {
  80. return false;
  81. }
  82. }
  83. endVarNamePos = endVarStringPos - 1;
  84. return true;
  85. }
  86.  
  87. bool StringContainsVariableStrings(const std::string &str)
  88. {
  89. std::string::size_type beginVarStringPos = 0;
  90. std::string::size_type endVarStringPos = 0;
  91. std::string::size_type beginVarNamePos = 0;
  92. std::string::size_type endVarNamePos = 0;
  93. bool ret = FindVariableString(str, 0, beginVarStringPos, endVarStringPos, beginVarNamePos, endVarNamePos);
  94. return ret;
  95. }
  96.  
  97. std::string GetVariableValue(
  98. const std::string &varName,
  99. const std::map<std::string, std::string> &env,
  100. bool &fromEnvMap, bool &valueContainsVariableStrings)
  101. {
  102. typedef std::map<std::string, std::string> my_map;
  103. fromEnvMap = false;
  104. valueContainsVariableStrings = false;
  105. std::string ret;
  106. my_map::const_iterator itFind = env.find(varName);
  107. if (itFind != env.end())
  108. {
  109. ret = (*itFind).second;
  110. if (!ret.empty())
  111. {
  112. fromEnvMap = true;
  113. valueContainsVariableStrings = StringContainsVariableStrings(ret);
  114. }
  115. }
  116. if (ret.empty())
  117. {
  118. ret = ::getenv(varName.c_str());
  119. }
  120. return ret;
  121. }
  122.  
  123. ::boost::xpressive::sregex GetRegex()
  124. {
  125. namespace xpr = ::boost::xpressive;
  126. xpr::sregex ret =
  127. "%" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '%'
  128. | "%(" >> (xpr::s1 = +(xpr::_w | xpr::_s)) >> ')'
  129. | "%[" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> ']'
  130. | "%{" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '}'
  131. | "$(" >> (xpr::s1 = +(xpr::_w | xpr::_s)) >> ')'
  132. | "$[" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> ']'
  133. | "${" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '}'
  134. | "#(" >> (xpr::s1 = +(xpr::_w | xpr::_s)) >> ')'
  135. | "#[" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> ']'
  136. | "#{" >> (xpr::s1 = +(xpr::_w | xpr::_s | "(" | ")")) >> '}';
  137. return ret;
  138. }
  139.  
  140. struct string_formatter
  141. {
  142. typedef std::map<std::string, std::string> env_map;
  143. env_map env;
  144. mutable bool valueContainsVariables;
  145. string_formatter()
  146. {
  147. valueContainsVariables = false;
  148. }
  149. template<typename Out>
  150. Out operator()(::boost::xpressive::smatch const& what, Out out) const
  151. {
  152. bool fromEnvMap;
  153. bool valueContainsVariableStrings;
  154. std::string value = GetVariableValue(
  155. what.str(1), env, fromEnvMap, valueContainsVariableStrings);
  156. if (fromEnvMap && !value.empty() && valueContainsVariableStrings)
  157. {
  158. valueContainsVariables = true;
  159. }
  160. if (value.empty())
  161. {
  162. value = what[0];
  163. }
  164. if (!value.empty())
  165. {
  166. out = std::copy(value.begin(), value.end(), out);
  167. }
  168. return out;
  169. }
  170. };
  171.  
  172. std::string ExpandVarsR(
  173. const std::string &original,
  174. const std::map<std::string, std::string> &env)
  175. {
  176. std::string ret = original;
  177. if (original.empty())
  178. {
  179. return ret;
  180. }
  181. string_formatter fmt;
  182. fmt.env = env;
  183. fmt.valueContainsVariables = false;
  184. ::boost::xpressive::sregex envar = GetRegex();
  185. ret = ::boost::xpressive::regex_replace(original, envar, fmt);
  186. if (fmt.valueContainsVariables)
  187. {
  188. std::string newValue;
  189. std::string prevValue = ret;
  190. do
  191. {
  192. fmt.valueContainsVariables = false;
  193. newValue = ::boost::xpressive::regex_replace(prevValue, envar, fmt);
  194. if (0 == prevValue.compare(newValue))
  195. {
  196. break;
  197. }
  198. prevValue.erase();
  199. prevValue = newValue;
  200. }
  201. while (fmt.valueContainsVariables);
  202. if (0 != ret.compare(newValue))
  203. {
  204. ret = newValue;
  205. }
  206. }
  207. return ret;
  208. }
  209.  
  210. std::string GetDateFormatStringExpandVars(const std::string& langCode)
  211. {
  212. if (
  213. 0 == langCode.compare(0, 2, "en")
  214. || 0 == langCode.compare(0, 2, "EN")
  215. )
  216. {
  217. return std::string("${month}/${day}/${year}");
  218. }
  219. else if (
  220. 0 == langCode.compare(0, 2, "fr")
  221. || 0 == langCode.compare(0, 2, "FR")
  222. )
  223. {
  224. return std::string("${day}/${month}/${year}");
  225. }
  226. else if (
  227. 0 == langCode.compare(0, 2, "ja")
  228. || 0 == langCode.compare(0, 2, "JA")
  229. || 0 == langCode.compare(0, 2, "jp")
  230. || 0 == langCode.compare(0, 2, "JP")
  231. )
  232. {
  233. return std::string("${year}/${day}/${month}");
  234. }
  235. return std::string("${month}/${day}/${year}");
  236. }
  237.  
  238. std::string GetDateStringExpandVarsR(
  239. const std::string &langCode, int month, int day, int year)
  240. {
  241. std::string fmt = GetDateFormatStringExpandVars(langCode);
  242. std::map<std::string,std::string> env{
  243. {"month", std::to_string(month)},
  244. {"day", std::to_string(day)},
  245. {"year", std::to_string(year)}
  246. };
  247. std::string ret = ExpandVarsR(fmt, env);
  248. return ret;
  249. }
  250.  
  251. int main()
  252. {
  253. std::cout << GetDateStringExpandVarsR("en", 11, 7, 2018) << "\n";
  254. return 0;
  255. }
  256.  
Success #stdin #stdout 0s 15360KB
stdin
Standard input is empty
stdout
11/7/2018