fork download
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <functional>
  4. #include <vector>
  5. #include <stdexcept>
  6. #include <map>
  7.  
  8. // Die ist ganz nützlich.
  9. template<typename CharT,
  10. typename Traits>
  11. inline std::basic_string<CharT, Traits>& rtrim(std::basic_string<CharT, Traits>& s, std::ctype<CharT> const& facet)
  12. {
  13. s.erase( std::find_if(s.rbegin(), s.rend(), [&](CharT ch){ return !facet.is( std::ctype_base::space, ch ); }).base(), std::end(s) );
  14. return s;
  15. }
  16.  
  17. template<typename Exception = std::logic_error>
  18. void Assert( bool b, std::string const& what = std::string() )
  19. {
  20. if(!b)
  21. throw Exception(what);
  22. }
  23.  
  24. template<typename CharT,
  25. typename Traits,
  26. typename Alloc>
  27. inline std::basic_istream<CharT, Traits>& checked_getline( std::basic_istream<CharT, Traits>& is, std::basic_string<CharT, Traits, Alloc>& str, CharT delim, CharT NotAllowed )
  28. {
  29. typedef std::basic_istream<CharT, Traits> istream_t;
  30. typedef std::basic_string<CharT, Traits, Alloc> string_t;
  31.  
  32. typename string_t::size_type extracted = 0;
  33. const typename string_t::size_type max_size = str.max_size();
  34.  
  35. typename std::ios_base::iostate err = std::ios_base::goodbit;
  36. typename istream_t::sentry sentry(is, true);
  37.  
  38. if (sentry)
  39. try
  40. {
  41. str.erase();
  42.  
  43. const typename Traits::int_type eof = Traits::eof();
  44.  
  45. typename Traits::int_type ich = is.rdbuf()->sgetc();
  46.  
  47. #define BREAK_WITH(a,b) \
  48. if( a ) \
  49. { \
  50. b; \
  51. break; \
  52. }
  53.  
  54. while( extracted < max_size )
  55. {
  56. BREAK_WITH( Traits::eq_int_type(ich, eof),
  57. err |= std::ios_base::eofbit )
  58.  
  59. auto ch = Traits::to_char_type(ich);
  60.  
  61. BREAK_WITH( Traits::eq(ch, delim),
  62. (++extracted, is.rdbuf()->sbumpc()) )
  63.  
  64. BREAK_WITH( Traits::eq(ch, NotAllowed),
  65. err |= std::ios_base::failbit )
  66.  
  67. str += ch;
  68.  
  69. ++extracted;
  70.  
  71. ich = is.rdbuf()->snextc();
  72. }
  73. }
  74. catch(...)
  75. {
  76. is.setstate(std::ios_base::badbit);
  77. }
  78.  
  79.  
  80. if (extracted == 0)
  81. err |= std::ios_base::failbit;
  82.  
  83. if (err != std::ios_base::goodbit)
  84. is.setstate(err);
  85.  
  86. return is;
  87. }
  88.  
  89. #include <memory>
  90.  
  91. template<typename CharT,
  92. typename Traits = std::char_traits<CharT>,
  93. typename ValueT = std::basic_string<CharT, Traits> >
  94. struct Node
  95. {
  96. typedef CharT char_type;
  97. typedef Traits traits_type;
  98.  
  99. typedef std::basic_string<CharT, Traits> key_type;
  100. typedef ValueT value_type;
  101.  
  102. std::basic_string<CharT, Traits> const name;
  103.  
  104. Node( std::basic_string<CharT, Traits> const& name = "Root" ):
  105. name(name) {}
  106.  
  107. std::map<key_type, value_type> entries;
  108.  
  109. std::vector<std::shared_ptr<Node>> child_nodes; // Darf *nicht* verändert werden - Inhalt wird gelöscht
  110. };
  111.  
  112. template<typename CharT,
  113. typename Traits>
  114. std::basic_istream<CharT, Traits>& ws_facet(std::basic_istream<CharT, Traits>& is, std::ctype<CharT> const& facet)
  115. {
  116. typename std::basic_istream<CharT, Traits>::sentry sentry(is, true);
  117.  
  118. if( sentry )
  119. {
  120. typename Traits::int_type const eof = Traits::eof();
  121.  
  122. typename Traits::int_type ch = is.rdbuf()->sgetc();
  123.  
  124. while( !Traits::eq_int_type(ch, eof)
  125. && facet.is( std::ctype_base::space, Traits::to_char_type(ch) ) )
  126. ch = is.rdbuf()->snextc();
  127.  
  128. if( Traits::eq_int_type(ch, eof) )
  129. is.setstate( std::ios_base::eofbit );
  130. }
  131.  
  132. return is;
  133. }
  134.  
  135. template<typename CharT,
  136. typename Traits,
  137. typename ValueT>
  138. std::basic_istream<CharT, Traits>& operator>>( std::basic_istream<CharT, Traits>& is, Node<CharT, Traits, ValueT>& node )
  139. {
  140. typedef std::basic_string<CharT, Traits> string_t;
  141.  
  142. typedef Node<CharT, Traits, ValueT> node_t;
  143.  
  144. auto const& ctype_facet = std::use_facet<std::ctype<CharT>>( is.getloc() );
  145.  
  146. typename Traits::int_type const open_brace = Traits::to_int_type(ctype_facet.widen('[')),
  147. comment_char = Traits::to_int_type(ctype_facet.widen('#')),
  148. forward_slash = Traits::to_int_type(ctype_facet.widen('/'));
  149.  
  150. CharT const separator = ctype_facet.widen('='),
  151. close_brace = ctype_facet.widen(']'),
  152. newline = ctype_facet.widen('\n');
  153.  
  154. while( ws_facet(is, ctype_facet).good() )
  155. {
  156. typename Traits::int_type ch = is.rdbuf()->sgetc();
  157.  
  158. if( Traits::eq_int_type(ch, comment_char) )
  159. is.ignore( std::numeric_limits<std::streamsize>::max(), newline );
  160.  
  161. else if( Traits::eq_int_type(ch, open_brace) ) /// Entweder eine neue Node wird eingeleitet, oder diese wird geschlossen ( [/...] )
  162. {
  163. ws_facet(is.ignore(), ctype_facet);
  164.  
  165. if( Traits::eq_int_type(is.rdbuf()->sgetc(), forward_slash) )
  166. {
  167. ws_facet(is.ignore(), ctype_facet);
  168.  
  169. for( auto const& c : node.name )
  170. Assert( Traits::eq_int_type( is.rdbuf()->sbumpc(), Traits::to_int_type(c) ), "Invalid closing tag!" );
  171.  
  172. ws_facet(is, ctype_facet);
  173.  
  174. Assert( Traits::eq_int_type( is.rdbuf()->sbumpc(), Traits::to_int_type(close_brace) ), "Missing ']' character at closing tag!" );
  175.  
  176. break; /// Beenden.
  177. }
  178. else // Eine neue, verschachtelte Node
  179. {
  180. string_t name;
  181.  
  182. checked_getline( is, name, close_brace, newline );
  183.  
  184. Assert( is.good(), "Invalid syntax in node title!" );
  185.  
  186. Assert( !rtrim(name, ctype_facet).empty(), "Empty node title!" );
  187.  
  188. node.child_nodes.push_back( std::shared_ptr<node_t>{new node_t{name}} );
  189.  
  190. Assert( is >> *node.child_nodes.back(), "Error while parsing sub-node!" );
  191. }
  192. }
  193. else /// Eine Key-Value zuweisung
  194. {
  195. std::pair<string_t, ValueT> pair;
  196.  
  197. checked_getline( is, pair.first, separator, newline );
  198.  
  199. Assert( is.good(), "Invalid syntax in key-value assignment!" );
  200.  
  201. Assert( !rtrim(pair.first, ctype_facet).empty(), "Empty key!" );
  202.  
  203. Assert( is >> pair.second, "Error while reading value type!" ); /// Hier wird der value eingelesen.
  204.  
  205. node.entries.insert( std::move(pair) );
  206. }
  207. }
  208.  
  209. return is;
  210. }
  211.  
  212. #include <sstream>
  213.  
  214. int main()
  215. {
  216. std::istringstream stream{
  217. R"(
  218. [Schurke]
  219. Str=12
  220. Dex= 17
  221. Int=4
  222. [/Schurke]
  223.  
  224. [Krieger]
  225. Str=18
  226. Dex=10
  227. Int=2
  228. [/Krieger]
  229. )" };
  230.  
  231. Node<char> node;
  232. stream >> node;
  233.  
  234. for( auto sub_node : node.child_nodes )
  235. {
  236. std::cout << "Name: " << sub_node->name << '\n';
  237. for( auto const& pair : sub_node->entries )
  238. std::cout << pair.first << " : " << pair.second << '\n';
  239. }
  240. }
  241.  
Success #stdin #stdout 0s 2996KB
stdin
Standard input is empty
stdout
Name: Schurke
Dex : 17
Int : 4
Str : 12
Name: Krieger
Dex : 10
Int : 2
Str : 18