"A": "1"
"A.B": "2"
"A.C": "3"
How to get the value of A.B if i iterate through the ptree it works. if i try
to get value of pt.get_child("A\.B").get_value<std::string>(). i get the following exception
terminate called after throwing an instance of boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::property_tree::ptree_bad_path> >'
what(): No such node
please find the complete code below
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
#include <string>
#include <iterator>
using boost::property_tree::ptree;
/* Indent Json Output */
std::string indent(int level) {
std::string s;
for (int i = 0; i < level; i++) s += " ";
return s;
}
/* Print tree in json format */
void printTree(ptree & pt, int level) {
if (pt.empty()) {
std::cerr << "\"" << pt.data() << "\"";
} else {
if (level) std::cerr << std::endl;
std::cerr << indent(level) << "{" << std::endl;
for (ptree::iterator pos = pt.begin(); pos != pt.end();) {
std::cerr << indent(level + 1) << "\"" << pos-> first << "\": ";
printTree(pos->second, level + 1);
++pos;
if (pos != pt.end()) {
std::cerr << ",";
}
std::cerr << std::endl;
}
std::cerr << indent(level) << " }";
}
return;
}
int main()
{
ptree pt;
read_ini("sample.ini", pt);
printTree(pt, 0);
std::cout << pt.get_child("A.B").get_value<std::string>() << std::endl; //tries to resolve A.B to two nodes
std::cout << pt.get_child("A\\.B").get_value<std::string>() << std::endl; //error
}
sample.ini
A=1
A.B=2
A.C=3
You can use alternative path delimiters, but it's a bit tricky and not very well documented.
You have to temporarily specify an alternative path separator:
Live On Coliru
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;
int main() {
ptree pt;
pt.put("a.b", "first");
pt.put(ptree::path_type("a|complicated.name", '|'), "second");
write_ini(std::cout, pt);
}
Prints
[a]
b=first
complicated.name=second
Related
In my application I'm calling different functions based on the message key received via network. But my implementation isn't that effective as it consists of exhaustive search for the key in the std::vector<std::string>. I'm thinking of using std::unordered_map<std::string, <fun>> but don't know how to map it to a function and also call that function by passing the required arguments. This is my current implementation:
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> msg_key_list;
msg_key_list.emplace_back("key1");
msg_key_list.emplace_back("key2");
msg_key_list.emplace_back("key3");
msg_key_list.emplace_back("key4");
msg_key_list.emplace_back("key5");
char buff[2048];
ssize_t data_len;
while (true) {
// receive data from network
std::string msg(buff, data_len);
std::string::size_type pos = msg.find_first_of(",");
std::string key = msg.substr(0, pos - 1);
if (key == msg_key_list.at(0)) {
// validate the message received
bool valid;
if (!valid) {
std::cerr << "Invalid data: ";
std::cerr << __FILE__ << ", " << __PRETTY_FUNCTION__ << ", " << __LINE__ << "\n";
continue;
}
std::string val(buff + pos, msg.size() - pos);
// fun1(val);
} else if (key == msg_key_list.at(1)) {
// validate the message received
bool valid;
if (!valid) {
std::cerr << "Invalid data: ";
std::cerr << __FILE__ << ", " << __PRETTY_FUNCTION__ << ", " << __LINE__ << "\n";
continue;
}
std::string val(buff + pos, msg.size() - pos);
// fun2(val);
} else if (key == msg_key_list.at(2)) {
// validate the message received
bool valid;
if (!valid) {
std::cerr << "Invalid data: ";
std::cerr << __FILE__ << ", " << __PRETTY_FUNCTION__ << ", " << __LINE__ << "\n";
continue;
}
std::string val(buff + pos, msg.size() - pos);
// fun3(val);
} else if (key == msg_key_list.at(3)) {
// validate the message received
bool valid;
if (!valid) {
std::cerr << "Invalid data: ";
std::cerr << __FILE__ << ", " << __PRETTY_FUNCTION__ << ", " << __LINE__ << "\n";
continue;
}
std::string val(buff + pos, msg.size() - pos);
// fun4(val);
} else if (key == msg_key_list.at(4)) {
// validate the message received
bool valid;
if (!valid) {
std::cerr << "Invalid data: ";
std::cerr << __FILE__ << ", " << __PRETTY_FUNCTION__ << ", " << __LINE__ << "\n";
continue;
}
std::string val(buff + pos, msg.size() - pos);
// fun5(val);
}
}
}
I made an example of how I whould approach this (if all handlers would share the same function signature). I also avoid the string copying in the message handler because that would slow things done unecessarily.
#include <iostream>
#include <stdexcept>
#include <vector>
#include <map>
#include <string>
//-----------------------------------------------------------------------------
// function signature of your message handlers
using handler_t = void(*)(const std::string_view&);
//-----------------------------------------------------------------------------
// handler functions
void handler_1(const std::string_view& msg)
{
// validate data here
std::cout << "handler 1 : " << msg << std::endl;
};
void handler_2(const std::string_view& msg)
{
std::cout << "handler 2 : " << msg << std::endl;
};
//-----------------------------------------------------------------------------
// handler selection
void handle_message(const std::string& buffer)
{
static const std::map<std::string_view, handler_t> handler_map
{
{"key1",handler_1},
{"key2",handler_2}
};
try
{
// find location of first ',' (if any)
// also ensure the ',' is not too far back for splitting
auto index = buffer.find_first_of(',');
if ((index != std::string::npos) && (index < (buffer.length() - 1)))
{
auto pos = buffer.begin() + index;
// No need to copy data to seperate strings
// string_views will do.
std::string_view key{ buffer.begin(), pos };
std::string_view data{ pos + 1, buffer.end() };
// lookup handler, not if no handler is found
// a std::out_of_range exception will be thrown
auto handler = handler_map.at(key);
// call the handler
handler(data);
}
}
catch (const std::out_of_range&)
{
// todo decide what you want to do with incorrect messages here
}
}
//-----------------------------------------------------------------------------
// and handle a test message in main
int main()
{
const std::string data{ "key1,Hello" };
handle_message(data);
}
I have the following code, where I try to insert values into a multimap of 2 strings, but I keep getting an error that I cannot understand. I've been trying to solve this for hours.
The whole point of the program is to sort the lines of a dictionary based on the automatic sorting of the multimap insertion.
// sort_entries_of_multiple_dictionaries.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <iomanip>
#include <sstream>
// Prototypes
int indexDict(std::multimap<std::string, std::string>& dict);
int main()
{
std::multimap<std::string, std::string> dict;
if(indexDict(dict) == 0)
return 0;
}
int indexDict(std::multimap<std::string, std::string>& dict)
{
std::ifstream inputFile{ "output.txt", std::ios::in };
std::string currentDictEntry{};
size_t currentLine{};
if (!inputFile)
{
std::cerr << "input.txt FILE NOT FOUND in the current directory" << std::endl;
system("pause");
return 0;
}
while (std::getline(inputFile, currentDictEntry))
{
//std::cout << currentDictEntry << std::endl; // TO DELETE
std::string currentWord{};
size_t delimiterPos = currentDictEntry.find('\t', 0);
if (delimiterPos == std::string::npos)
std::cerr << "ERROR. Delimiter \"<b>\" not found in line " << currentLine << std::endl;
else
{
//std::cout << "pos of \\t = " << delimiterPos << std::endl; // TO DELETE
for (char& ch : currentDictEntry)
{
if (ch != '\t')
{
currentWord += ch;
}
else
break;
}
std::cout << currentWord /* << '|' */ << std::endl; // TO DELETE
auto value = currentDictEntry.substr(delimiterPos, std::string::npos);
std::cout << "size= " << value.size() << '|' << value << std::endl;
dict.insert( currentWord, currentWord/*, value*/ );
}
if (currentLine == 50) return 0; // TO DELETE
currentLine++;
}
return 1;
}
if (currentLine == 50) return 0; // TO DELETE
currentLine++;
}
return 1;
}
The error I keep getting is:
unary '++': '_Iter' does not define this operator or a conversion to a type acceptable to the predefined operator
illegal indirection
as #Evg said, it accepts a std::pair
dict.insert(std::make_pair(currentWord, value));
if I understand your intention correctly, you don't want to save the \t into your result, so add 1 after delimiterPos to get the correct value:
auto value = currentDictEntry.substr(delimiterPos + 1, std::string::npos);
test run. output.txt:
4 d
1 a
2 b
3 c
0
output:
"0" - ""
"1" - "a"
"2" - "b"
"3" - "c"
"4" - "d"
full code:
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <iomanip>
#include <sstream>
// Prototypes
int indexDict(std::multimap<std::string, std::string>& dict);
int main()
{
std::multimap<std::string, std::string> dict;
if (indexDict(dict) == 0)
return 0;
for (auto& i : dict) {
std::cout << "\"" << i.first << "\" - \"" << i.second << "\"\n";
}
}
int indexDict(std::multimap<std::string, std::string>& dict)
{
std::ifstream inputFile{ "output.txt", std::ios::in };
std::string currentDictEntry{};
size_t currentLine{};
if (!inputFile)
{
std::cerr << "output.txt FILE NOT FOUND in the current directory" << std::endl;
system("pause");
return 0;
}
while (std::getline(inputFile, currentDictEntry))
{
//std::cout << currentDictEntry << std::endl; // TO DELETE
std::string currentWord{};
size_t delimiterPos = currentDictEntry.find('\t', 0);
if (delimiterPos == std::string::npos)
std::cerr << "ERROR. Delimiter \"<b>\" not found in line " << currentLine << std::endl;
else
{
//std::cout << "pos of \\t = " << delimiterPos << std::endl; // TO DELETE
for (char& ch : currentDictEntry)
{
if (ch != '\t')
{
currentWord += ch;
}
else
break;
}
std::cout << currentWord /* << '|' */ << std::endl; // TO DELETE
auto value = currentDictEntry.substr(delimiterPos + 1, std::string::npos);
std::cout << "size= " << value.size() << '|' << value << std::endl;
dict.insert(std::make_pair(currentWord, value));
}
if (currentLine == 50) return 0; // TO DELETE
currentLine++;
}
return 1;
}
small mistakes in your code: you don't need <algorithm> and <vector>. also your error message said input.txt instead of output.txt.
I Change dict.insert( currentWord, currentWord/*, value*/ ); To dict.insert({ currentWord,currentWord }); and error Has solved
"A": "1"
"A.B": "2"
"A.C": "3"
How to get the value of A.B if i iterate through the ptree it works. if i try
to get value of pt.get_child("A\.B").get_value<std::string>(). i get the following exception
terminate called after throwing an instance of boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::property_tree::ptree_bad_path> >'
what(): No such node
please find the complete code below
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
#include <string>
#include <iterator>
using boost::property_tree::ptree;
/* Indent Json Output */
std::string indent(int level) {
std::string s;
for (int i = 0; i < level; i++) s += " ";
return s;
}
/* Print tree in json format */
void printTree(ptree & pt, int level) {
if (pt.empty()) {
std::cerr << "\"" << pt.data() << "\"";
} else {
if (level) std::cerr << std::endl;
std::cerr << indent(level) << "{" << std::endl;
for (ptree::iterator pos = pt.begin(); pos != pt.end();) {
std::cerr << indent(level + 1) << "\"" << pos-> first << "\": ";
printTree(pos->second, level + 1);
++pos;
if (pos != pt.end()) {
std::cerr << ",";
}
std::cerr << std::endl;
}
std::cerr << indent(level) << " }";
}
return;
}
int main()
{
ptree pt;
read_ini("sample.ini", pt);
printTree(pt, 0);
std::cout << pt.get_child("A.B").get_value<std::string>() << std::endl; //tries to resolve A.B to two nodes
std::cout << pt.get_child("A\\.B").get_value<std::string>() << std::endl; //error
}
sample.ini
A=1
A.B=2
A.C=3
You can use alternative path delimiters, but it's a bit tricky and not very well documented.
You have to temporarily specify an alternative path separator:
Live On Coliru
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;
int main() {
ptree pt;
pt.put("a.b", "first");
pt.put(ptree::path_type("a|complicated.name", '|'), "second");
write_ini(std::cout, pt);
}
Prints
[a]
b=first
complicated.name=second
I need to output the 5 largest files from the directory. For this, I use a boost filesystem c++. In the process of writing the program, I encountered difficulties. I can output all files from the directory, file size, file creation date and file attributes. In the vector I put the names of the files, but I just can not figure out how to sort by size. I need to output the 5 largest files from the specified directory. I think that you must first sort by file size by descending. That is, from a larger value to a smaller one. And then the scans are not needed. Most likely it needs to be done in a loop. Help me please.
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
void ShowAttributes(DWORD attributes);
void AttribFile(const char* str);
void Attrib();
int main(int argc, char* argv[])
{
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
if (argc < 2)
{
cout << "Using Name Directory" << endl;
return 1;
}
path Part(argv[1]);
try
{
if (exists(Part))
{
if (is_regular_file(Part))
{
cout << Part << " Size " << file_size(Part) << " bytes ";
time_t Time = last_write_time(Part);
cout << asctime(localtime(&Time)) << endl;
}
else if (is_directory(Part))
{
cout << "Directory " << Part << " include:" << endl;
vector<string> vecList;
for (auto j : directory_iterator(Part))
vecList.push_back(j.path().filename().string());
sort(vecList.begin(), vecList.end());
string filePath;
for (auto i : vecList)
{
cout << " " << i;
filePath = Part.parent_path().string() + "/" + i;
if (is_regular_file(filePath))
{
if (Is_Executable_File(filePath))
cout << "*";
cout << " Size " << file_size(filePath) << " bytes ";
time_t Time = last_write_time(Part);
cout << asctime(localtime(&Time)) << endl;
AttribFile(filePath.c_str());
}
cout << endl;
}
}
}
else
cout << Part << " Erroe!" << endl;
}
catch (const filesystem_error& ex)
{
cout << ex.what() << endl;
}
return 0;
}
void ShowAttributes(DWORD attributes)
{
if (attributes & FILE_ATTRIBUTE_ARCHIVE)
cout << " archive" << endl;
if (attributes & FILE_ATTRIBUTE_DIRECTORY)
cout << " directory" << endl;
if (attributes & FILE_ATTRIBUTE_HIDDEN)
cout << " hidden" << endl;
if (attributes & FILE_ATTRIBUTE_NORMAL)
cout << " normal" << endl;
if (attributes & FILE_ATTRIBUTE_READONLY)
cout << " read only" << endl;
if (attributes & FILE_ATTRIBUTE_SYSTEM)
cout << " system" << endl;
if (attributes & FILE_ATTRIBUTE_TEMPORARY)
cout << " temporary" << endl;
}
void AttribFile(const char* str)
{
DWORD attributes;
attributes = GetFileAttributesA(str);
ShowAttributes(attributes);
}
void Attrib()
{
char filename[MAX_PATH];
DWORD attributes;
cout << "Name of file: ";
cin >> filename;
attributes = GetFileAttributesA(filename);
ShowAttributes(attributes);
}
create a class or struct to hold the information you need on each file, e.g.
struct MyFile
{
std::string name;
size_t size;
}
create a vector of these and read all files from your folder
then sort the vector and give a custom comparison (e.g. in form of a lambda), see Sorting a vector of custom objects for details on that
Here's a program based on just the standard library that does what you seem to intend:
Live On Coliru
Update: Using C++11 and Boost Filesystem instead: Live On Coliru
#include <algorithm>
#include <filesystem>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
namespace fs = std::filesystem;
struct tm *last_modified(fs::path const &p) {
auto ftime = fs::last_write_time(p);
auto cftime = decltype(ftime)::clock::to_time_t(ftime);
return std::localtime(&cftime);
}
bool is_executable(fs::path const& p) {
return fs::perms::none != (fs::status(p).permissions() &
(fs::perms::owner_exec |
fs::perms::group_exec |
fs::perms::others_exec));
}
void report(fs::path const& file) {
if (is_executable(file))
std::cout << "*";
std::cout << file << "\tSize:" << fs::file_size(file);
std::cout << "\tModified:" << std::asctime(last_modified(file));
}
template <typename Accessor, typename Cmp = std::less<> >
static auto compare_by(Accessor&& f, Cmp cmp = {}) {
return [f=std::forward<Accessor>(f),cmp](auto const& a, auto const& b) {
return cmp(f(a), f(b));
};
}
int main(int argc, char *argv[]) {
if (argc < 2) {
std::cout << "Using: " << argv[0] << " [Name|Directory]" << std::endl;
return 1;
}
fs::path filespec(argv[1]);
try {
if (is_regular_file(filespec)) {
// print
report(filespec);
} else if (is_directory(filespec)) {
std::cout << "Directory " << filespec << " include:" << std::endl;
std::vector<fs::directory_entry> const entries { fs::directory_iterator{filespec}, {} };
// filter just files
std::vector<fs::path> files;
std::remove_copy_if(entries.begin(), entries.end(),
back_inserter(files),
[](auto& de) { return de.is_directory(); });
// get the top 5, or fewer
auto b = files.begin(),
top5 = b + std::min(5ul, files.size()),
e = files.end();
// ordered by size, descending
std::partial_sort(b, top5, e,
compare_by([](auto& p) { return fs::file_size(p); }, std::greater<>{}));
files.erase(top5, e);
// print
for (auto& f : files)
report(f);
} else {
std::cout << filespec << " Error!" << std::endl;
}
} catch (const fs::filesystem_error &ex) {
std::cout << ex.what() << std::endl;
}
}
Prints, e.g. for ./a.out /usr/lib:
Directory "/usr/lib/" include:
"/usr/lib/libruby-1.9.1-static.a" Size:3654748 Modified:Wed Nov 19 21:41:25 2014
"/usr/lib/libruby-1.9.1.so.1.9.1" Size:2087600 Modified:Wed Nov 19 21:41:20 2014
"/usr/lib/libruby-1.9.1.so" Size:2087600 Modified:Wed Nov 19 21:41:20 2014
"/usr/lib/libruby-1.9.1.so.1.9" Size:2087600 Modified:Wed Nov 19 21:41:20 2014
"/usr/lib/libc++.so.1" Size:1460461 Modified:Mon Sep 8 20:01:17 2014
I'm having trouble with std::stringstream. My function as seen below returns absolutely nothing. Even when trying a stringstream outside of the template function it still returns nothing when .str() is called.
template < class T > std::string toString( const T &t )
{
std::stringstream temp;
temp << t;
std::cout << temp.str() << std::endl;
return temp.str();
}
std::string test = "test" + toString( 1 );
std::cout << test << std::endl;
std::stringstream stream;
stream << "test" << 1;
std::cout << stream.str() << std::endl;
Both of these output only "test"
Fixed
Had to remove _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC from my preprocessor macros.
Try ostringstream instead of stringstream.
== UPDATE ==
I compiled your code with GCC 4.6.1, and it works as-is:
#include <iostream>
#include <sstream>
using namespace std;
template < class T > std::string toString( const T &t )
{
std::stringstream temp;
temp << t;
std::cout << temp.str() << std::endl;
return temp.str();
}
int main()
{
std::string test = "test" + toString( 1 );
std::cout << test << std::endl;
std::stringstream stream;
stream << "test" << 1;
std::cout << stream.str() << std::endl;
return 0;
}
Output:
1
test1
test1
#include <iostream>
#include <sstream>
#include <string>
template < class T > std::string toString( const T &t )
{
std::stringstream temp;
temp << t;
std::cout << temp.str() << std::endl;
return temp.str();
}
int main(){
std::string test = "test" + toString( 1 );
std::cout << test << std::endl;
std::stringstream stream;
stream << "test" << 1;
std::cout << stream.str() << std::endl;
}
Outputs
1
test1
test1
For me with Clang 3.1, GCC 4.4.5 and MSVC 10, so your problem lies elsewhere. Please try just the code above in a new project and see if the problem persists. If not, the suggestions by #Industrial-antidepressant sounds quite realistic, i.e. that you have a better matching overload lying around somewhere.