Converting a code from c++ 11 to c++ 98? - c++

I'm a beginner in c++ and my compiler (c-free 5.0) can't compile this code :-
#include <iostream>
#include <map>
#include <string>
int main()
{
std::string input = "slowly";
std::map<char, int> occurrences;
for (char character : input)
{
occurrences[character] += 1;
}
for (auto& entry : occurrences)
{
std::cout << entry.first << '=' << entry.second << std::endl;
}
}
Can anyone please tell me how to make it work in my compiler ?

Convert the range-based for to loops using iterator
Stop using auto and write the type manually
code:
#include <iostream>
#include <map>
#include <string>
int main()
{
std::string input = "slowly";
std::map<char, int> occurrences;
for (std::string::iterator character = input.begin(); character != input.end(); character++)
{
occurrences[*character] += 1;
}
for (std::map<char, int>::iterator entry = occurrences.begin(); entry != occurrences.end(); entry++)
{
std::cout << entry->first << '=' << entry->second << std::endl;
}
}

Related

Boost Tokenizer strange symbols at start

#include <iostream>
#include <optional>
#include <string>
#include <boost/tokenizer.hpp>
int main() {
std::string a("http://website/some-path/,file1,file2");
char *ptr = (char *)a.c_str();
boost::char_separator<char> delim(",");
std::vector<std::string> pths{};
boost::tokenizer<boost::char_separator<char>> tokens(
std::string(ptr), delim);
std::optional<std::string> pref = std::nullopt;
for (const auto& tok : tokens) {
if (!pref) {
pref = tok;
std::cerr << "prfix is set: " << tok << std::endl;
continue;
}
pths.push_back(*pref + tok);
}
for(auto &t : pths) {
std::cout << t << std::endl;
}
}
My output:
prfix is set: �site/some-path/
�site/some-path/file1
�site/some-path/file2
The question is, what is wrong with the above? If I work with std::regex, it is fine.
EDIT: the scenario with *ptr is the one I actually had: the original string was passed to a function as char *, hence the above. This is to answer the comment by #273K.
A lot can be simplified, at once removing the problems:
Live On Coliru
#include <boost/tokenizer.hpp>
#include <iostream>
#include <optional>
#include <string>
auto generate(std::string const& a) {
boost::tokenizer tokens(a, boost::char_separator<char>{","});
std::optional<std::string> prefix;
std::vector<std::string> result;
for (const auto& tok : tokens) {
if (!prefix)
prefix = tok;
else
result.push_back(*prefix + tok);
}
return result;
}
int main() {
for (auto& t : generate("http://website/some-path/,file1,file2"))
std::cout << t << std::endl;
}
Prints
http://website/some-path/file1
http://website/some-path/file2

How can I find the positions from characters in a string with string::find?

I need the positions of characters in a string.
The String contains:
"username":"secret", "password":"also secret", "id":"secret too", "token":"secret"
and I need the positions of the quotation marks from the token that are bold: "token":"secret".
I have experimented with the code from http://www.cplusplus.com/reference/string/string/find
but everything didn't work. Can anyone help me?
Here is what i have tried but it only gives out a 0:
#include <iostream>
#include <string>
int main() {
std::string buffer("\"username\":\"secret\", \"password\":\"also secret\", \"id\":\"secret too\", \"token\":\"secret\"");
size_t found = buffer.find('"');
if (found == std::string::npos)std::cout << "something went wrong\n";
if (found != std::string::npos)
std::cout << "first " << '"' << " found at: " << found << '\n';
for (int j = 0; j <= 17; ++j) {
found = buffer.find('"');
found + 1, 6;
if (found != std::string::npos)
std::cout << "second " << '"' << " found at : " << found << '\n';
}
return 0;
There are so many possible solutions. So, it is hard to answer.
What basically needs to be done, is to iterate through the string, position by position, then check if the character is the searched one, and then do something with the result.
A first simple implementation could be:
#include <iostream>
#include <string>
const std::string buffer("\"username\":\"secret\", \"password\":\"also secret\", \"id\":\"secret too\", \"token\":\"secret\"");
int main() {
for (size_t position{}, counter{}; position < buffer.length(); ++position) {
if (buffer[position] == '\"') {
++counter;
std::cout << "Character \" number " << counter << " found at position " << position << '\n';
}
}
return 0;
}
But then, your question was about the usage of std::string.find(). In your implementation, you start always the search at the beginning of the std::string. And because of that, you will always find the same " at position 0.
Solution: After you have found the first match, use the resulting pos (incremented by one) as the second parameter to the std::string.find() function. Then you will start the search after the first found " and hence find the next one. And all this can be done in a normal for-loop.
See below the next easy example:
#include <iostream>
#include <string>
const std::string buffer("\"username\":\"secret\", \"password\":\"also secret\", \"id\":\"secret too\", \"token\":\"secret\"");
int main() {
for (size_t position{}, counter{}; std::string::npos != (position = buffer.find("\"", position)); ++position, ++counter) {
std::cout << "Character \" number " << counter << " found at position " << position << '\n';
}
return 0;
}
There are more solutions, depending on what you really want to do. You coud extract all keywords and data with a simple regex.
Something like this:
#include <iostream>
#include <string>
#include <regex>
#include <vector>
const std::regex re{ R"(\"([ a-zA-Z0-9]+)\")" };
const std::string buffer("\"username\":\"secret\", \"password\":\"also secret\", \"id\":\"secret too\", \"token\":\"secret\"");
int main() {
std::vector part(std::sregex_token_iterator(buffer.begin(), buffer.end(), re, 1), {});
std::cout << part[7] << '\n';
return 0;
}
Or, you can split everything into tokens and values. Like this:
#include <iostream>
#include <string>
#include <regex>
#include <vector>
#include <map>
#include <iomanip>
const std::regex re1{ "," };
const std::regex re2{ R"(\"([^\"]+)\")" };
const std::string buffer("\"username\":\"secret\", \"password\":\"also secret\", \"id\":\"secret too\", \"token\":\"secret\"");
int main() {
std::vector<std::string> block(std::sregex_token_iterator(buffer.begin(), buffer.end(), re1, -1), {});
std::map<std::string, std::string> entry{};
for (const auto& b : block) {
std::vector blockPart(std::sregex_token_iterator(b.begin(), b.end(), re2, 1), {});
entry[blockPart[0]] = blockPart[1];
}
for (const auto& [token, value] : entry)
std::cout << std::setw(20) << token << " --> " << value << '\n';
return 0;
}
But if you have a complex given format, like JSON, there are so many special cases that the only meaningful approach is to use an existing library.

Boost Spirit synthesised attribute confusion

I'm trying to parse input which has either a plus or minus character, followed by an X or Y character, followed by an unsigned integer.
(char_('+') | char_('-')) >> char_("xyXY") >> uint_
According to my reading of the docs, the synthesised attribute for this would be tuple<vector<char>,unsigned int> because the alternative parser (char | char) would be of type char, the char >> char("xyXY") would be vector<char>, and the vector<char> >> uint_ would be a tuple of the types, so tuple<vector<char>,unsigned int>. This fails to compile
qi\detail\assign_to.hpp(152) : error C2440: 'static_cast' : cannot convert from 'const char' to 'boost::tuples::tuple<T0,T1>'
Code:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
using namespace boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::tuple<std::vector<char>,unsigned int> output;
bool result = phrase_parse(first,last,(char_('+') | char_('-')) >> char_("xyXY") >> uint_,ascii::space,output);
if(result && first == last)
std::cout << "sign=" << boost::get<0>(output)[0] << ", xy=" << boost::get<0>(output)[1] << ", size=" << boost::get<1>(output) << '\n';
else
std::cerr << "Parse error\n";
}
I then tried tuple<char,char,unsigned int> as the attribute type:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
using namespace boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::tuple<char,char,unsigned int> output;
bool result = phrase_parse(first,last,(char_('+') | char_('-')) >> char_("xyXY") >> uint_,ascii::space,output);
if(result && first == last)
std::cout << "sign=" << boost::get<0>(output) << ", xy=" << boost::get<1>(output) << ", size=" << boost::get<2>(output) << '\n';
else
std::cerr << "Parse error\n";
}
This compiles but the output is incorrect. The first token of the input is parsed correctly, but the subsequent tokens aren't:
sign=-, xy= , size=0
I also tried as_string[]:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
using namespace boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::tuple<std::string,unsigned int> output;
bool result = phrase_parse(first,last,as_string[(char_('+') | char_('-')) >> char_("xyXY")] >> uint_,ascii::space,output);
if(result && first == last)
std::cout << "sign=" << boost::get<0>(output)[0] << ", xy=" << boost::get<0>(output)[1] << ", size=" << boost::get<1>(output) << '\n';
else
std::cerr << "Parse error\n";
}
This improved things as the x/y token got parsed, but not the third integer token:
sign=-, xy=Y, size=0
Please show me where I'm going wrong.
I'm using Spirit version 2.5.2 (from Boost 1.58.0) and Microsoft Visual Studio 2008.
Spirit library docs recommend to use Fusion tuple. I think I saw somewhere (can't find it now) that Boost tuple may not be fully compatible with Spirit library.
Here is your fixed example:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/sequence.hpp>
namespace qi = boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::fusion::tuple<char, char, unsigned int> output;
bool result = qi::phrase_parse(first, last, (qi::char_('+') | qi::char_('-')) >> qi::char_("xyXY") >> qi::uint_, qi::ascii::space, output);
if (result && first == last)
std::cout << "sign=" << boost::fusion::get<0>(output) << ", xy=" << boost::fusion::get<1>(output) << ", size=" << boost::fusion::get<2>(output) << '\n';
else
std::cerr << "Parse error\n";
return 0;
}
Output:
sign=-, xy=Y, size=512
Update: Actually I found here that it's possible to use boost::tuple but different header needs to be included: #include <boost/fusion/include/boost_tuple.hpp>.

Trying to print an unordered_map

I am writing a simple program to find anagrams. I am using a hash table with sorted strings as the keys, and the unsorted strings as the values. When I try to print the unordered_map (hash map) it gives me this error.
Error 1 error C2675: unary '++' : 'std::string' does not define this
operator or a conversion to a type acceptable to the predefined
operator c:\program files (x86)\microsoft visual studio
12.0\vc\include\xhash 672 1
#include <iostream>
#include <list>
#include <cstdlib>
#include <map>
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cstring>
void Anagrams(std::vector<std::string> &v){
std::unordered_map<std::string, std::string> wordTable;
char sortedString[256];
for (std::string tmp : v){
strcpy(sortedString, tmp.c_str());
std::sort(sortedString, sortedString + tmp.size());
std::string backToString(sortedString);
wordTable.insert(backToString, tmp);
}
std::cout << "Map contains" << std::endl;
std::cout << "mymap's buckets contain:\n";
for (unsigned i = 0; i < wordTable.bucket_count(); ++i) {
std::cout << "bucket #" << i << " contains:";
for (auto local_it = wordTable.begin(i); local_it != wordTable.end(i); ++local_it)
std::cout << " " << local_it->first << ":" << local_it->second;
std::cout << std::endl;
}
}
int main()
{
std::vector<std::string> words{ "debitcard", "badcredit", "cat", "act", "evils", "elvis" };
Anagrams(words);
return 0;
}
For some reason it thinks the iterator "local_it" is a string. Can anyone help?
The issue is that the std::unorderd_map::insert() function takes a std::pair<key, value>, not key, value:
wordTable.insert(std::make_pair(backToString, tmp));

Splitting string in specific format which was created from int vector

I wrote a program which creates comma separated string out of vector of int like below:
std::vector<unsigned int> Vec;
Vec.push_back(50);
Vec.push_back(60);
Vec.push_back(10);
Vec.push_back(20);
Vec.push_back(30);
Vec.push_back(2);
Vec.push_back(1);
std::stringstream lineNumString;
lineNumString.str(std::string());
lineNumString.clear();
std::copy(Vec.begin(), Vec.end(), std::ostream_iterator<unsigned int>(lineNumString, ","));
std::string lineString(lineNumString.str());
lineString = lineString.substr(0, lineString.length()-1);
std::cout << std::endl << lineString;
If you see output of above program is:
`50,60,10,20,30,2,1`
But I want to change my output in some different format. I want to have maximum THREE numbers on one line and next numbers to next line. Like below:
50,60,10,
20,30,2,
1
I tried creating child vectors from Vec and tried using them to create different strings. Then I tried splitting lineString and then used those strings.
Please let me know if there is any better way to achieve final output?
I am using VS2010. I can use BOOST features also.
Thanks.
The classic loop way:
#include <vector>
#include <iostream>
#include <sstream>
#include <iterator>
int main()
{
std::vector<unsigned int> Vec;
Vec.push_back(50);
Vec.push_back(60);
Vec.push_back(10);
Vec.push_back(20);
Vec.push_back(30);
Vec.push_back(2);
Vec.push_back(1);
for(auto it = Vec.begin(); it != Vec.end();)
{
std::cout << *it++;
if(it != Vec.end())
std::cout << ",";
if((it - Vec.begin()) % 3 == 0)
std::cout << std::endl;
}
return 0;
}
The Boost.spirit way:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <vector>
#include <string>
namespace karma = boost::spirit::karma;
int main()
{
std::vector<unsigned int> v = {50, 60, 10, 20, 30, 2, 1};
using karma::int_;
using karma::eol;
using karma::duplicate;
using karma::generate;
std::string out;
std::back_insert_iterator<std::string> it(out);
generate(it, int_ << "," << *(int_ << "," << int_ << "," << duplicate[ &int_ << eol << int_ << ","]), v);
out[out.size() - 1] = 0;
std::cout << out << std::endl;
return 0;
}
The little trick with duplicate: it duplicates attribute int_, which is mandatory, because predicate & consume it, in order to know if we display the end of the line (eol) or not.