How to store intermediate values of circular buffer iterator? - c++

I am a using a boost regex on a boost circular buffer and would like to "remember" positions where matches occur, what's the best way to do this? I tried the code below, but "end" seems to store the same values all the time! When I try to traverse from a previous "end" to the most recent "end" for example, it doesn't work!
boost::circular_buffer<char> cb(2048);
typedef boost::circular_buffer<char>::iterator ccb_iterator;
boost::circular_buffer<ccb_iterator> cbi(4);
//just fill the whole cbi with cb.begin()
cbi.push_back(cb.begin());
cbi.pushback(cb.begin());
cbi.pushback(cb.begin());
cbi.pushback(cb.begin());
typedef regex_iterator<circular_buffer<char>::iterator> circular_regex_iterator;
while (1)
{
//insert new data in circular buffer (omitted)
//basically reads data from file and pushes it back to cb
boost::circular_buffer<char>::iterator start,end;
circular_regex_iterator regexItr(
cb.begin(),
cb.end() ,
re, //expression of the regular expression
boost::match_default | boost::match_partial);
circular_regex_iterator last;
while(regexItr != last)
{
if((*regexItr)[0].matched == false)
{
//partial match
break;
}
else
{
// full match:
start = (*regexItr)[0].first;
end = (*regexItr)[0].second;
//I want to store these "end" positions to to use later so that I can
//traverse the buffer between these positions (matches).
//cbi stores positions of these matches, but this does not seem to work!
cbi.push_back(end);
//for example, cbi[2] --> cbi[3] traversal works only first time this
//loop is run!
}
++regexItr;
}
}

This isn't quite as much an answer as an attempt to reconstruct what you're doing. I'm making a simple circular buffer initialized from a string, and I traverse regex matches through that buffer and print the matched ranges. All seems to work fine.
I would not recommend storing the ranges themselves in a circular buffer; or at the very least the ranges should be stored in pairs.
Here's my test code:
#include <iostream>
#include <string>
#include <boost/circular_buffer.hpp>
#include <boost/regex.hpp>
#include "prettyprint.hpp"
typedef boost::circular_buffer<char> cb_char;
typedef boost::regex_iterator<cb_char::iterator> cb_char_regex_it;
int main()
{
std::string sample = "Hello 12 Worlds 34 ! 56";
cb_char cbc(8, sample.begin(), sample.end());
std::cout << cbc << std::endl; // (*)
boost::regex expression("\\d+"); // just match numbers
for (cb_char_regex_it m2, m1(cbc.begin(), cbc.end(), expression); m1 != m2; ++m1)
{
const auto & mr = *m1;
std::cout << "--> " << mr << ", range ["
<< std::distance(cbc.begin(), mr[0].first) << ", "
<< std::distance(cbc.begin(), mr[0].second) << "]" << std::endl;
}
}
(This uses the pretty printer to print the raw circular buffer; you can remove the line marked (*).)
Update: Here's a possible way to store the matches:
typedef std::pair<std::size_t, std::size_t> match_range;
typedef std::vector<match_range> match_ranges;
/* ... as before ... */
match_ranges ranges;
for (cb_char_regex_it m2, m1(cbc.begin(), cbc.end(), expression); m1 != m2; ++m1)
{
const auto & mr = *m1;
ranges.push_back(match_range(std::distance(cbc.begin(), mr[0].first), std::distance(cbc.begin(), mr[0].second)));
std::cout << "--> " << mr << ", range " << ranges.back() << std::endl;
}
std::cout << "All matching ranges: " << ranges << std::endl;

Related

Getting coefficients from a string

I have a project to write a program that receives a polynomial string from the user up to the 5th power (ex. x^3+6x^2+9x+24) and prints out all the real and imaginary roots. The coefficients should be stored in a dynamic array.
The problem is getting these coefficients from the string. One of the coefficients can be a 0 (ex. 2x^2-18) so I can't store the coefficients from left to right by using an increment, because in this case a=2, b=-18, and c has no value, which is wrong.
Another problem is if the coefficient is 1, because in this case nothing will be written beside the x for the program to read (ex. x^2-x+14). Another problem is if the user adds a space, several, or none (ex. x ^3 +4x^ 2- 12 x + 1 3).
I have been thinking of pseudocode for a long time now, but nothing is coming to mind. I thought of detecting numbers from left to right and reading numbers and stopping at x, but the first and second problems occur. I thought of finding each x and then checking the numbers before it, but the second problem occurs, and also I don't know how big the number the user inputs.
Here is another Regex that you can use to get your coefficients after deleting whitespace characters:
(\d*)(x?\^?)(\d*)
It uses groups (indicated by the brackets). Every match has 3 groups:
Your coefficient
x^n, x or nothing
The exponent
If (1) is null (e.g. does not exist), it means your coefficient is 1.
If (2) and (3) are null, you have the last single number without x.
If only (3) is null, you have a single x without ^n.
You can try some examples on online regex sites like this one, where you can see the results on the right.
There are many tutorials online how to use Regex with C++.
You should normalize your input string, for example, remove all space then parse coefficients.
Let see my example. Please change it for your case.
#include <iostream>
#include <regex>
#include <iterator>
#include <string>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[]) {
std::string input {argv[1]};
input.erase(remove_if(input.begin(), input.end(), isspace), input.end());
std::cout << input << std::endl;
std::vector<int> coeffs;
std::regex poly_regex(R"(\s*\+?\-?\s*\d*\s*x*\^*\s*\d*)");
auto coeff_begin = std::sregex_iterator(input.begin(), input.end(), poly_regex);
auto coeff_end = std::sregex_iterator();
for (std::sregex_iterator i = coeff_begin; i != coeff_end; ++i) {
std::smatch match = *i;
std::string match_str = match.str();
// std::cout << " " << match_str << "\n";
std::size_t plus_pos = match_str.find('+');
std::size_t minus_pos = match_str.find('-');
std::size_t x_pos = match_str.find('x');
if (x_pos == std::string::npos) {
std::cout << match_str.substr(plus_pos + 1) << std::endl;
} else if (x_pos == 0) {
std::cout << 1 << std::endl;
} else if (minus_pos != std::string::npos) {
if (x_pos - minus_pos == 1) std::cout << -1 << std::endl;
else std::cout << match_str.substr(minus_pos, x_pos - minus_pos) << std::endl;
}
else {
std::cout << match_str.substr(plus_pos + 1, x_pos - plus_pos - 1) << std::endl;
}
}
for (auto i: coeffs) std::cout << i << " ";
return 0;
}

How to get the elements of a tuple

I am creating a scrabble game and i need to have a basic score to words on the dictionary.
I used make_tuple and stored it inside my tuple. Is there a way to access elements in a tuple as if it was in a vector?
#include <iostream>
#include <tuple>
#include <string>
#include <fstream>
void parseTextFile()
{
std::ifstream words_file("scrabble_words.txt"); //File containing the words in the dictionary (english) with words that do not exist
std::ofstream new_words_file("test.txt"); //File where only existing words will be saved
std::string word_input;
std::tuple<std::string, int> tupleList;
unsigned int check_integrity;
int counter = 0;
while(words_file >> word_input)
{
check_integrity = 0;
for (unsigned int i = 0; i < word_input.length(); i++)
{
if((int)word_input[i] >= 97 && (int)word_input[i] <= 123) //if the letter of the word belongs to the alphabet
{
check_integrity++;
}
}
if(word_input.length() == check_integrity)
{
new_words_file << word_input << std::endl; //add the word to the new file
tupleList = std::make_tuple(word_input, getScore(word_input)); //make tuple with the basic score and the word
counter++; //to check if the amount of words in the new file are correct
std::cout << std::get<0>(tupleList) << ": " << std::get<1>(tupleList) << std::endl;
}
}
std::cout << counter << std::endl;
}
One would generally use a tuple when there are more than two values of different types to store. For just two values a pair is a better choice.
In your case what you want to achieve seems to be a list of word-value pairs. You can store them in a container like a vector but you can also store them as key-value pairs in a map. As you can see when following the link, an std::map is literally a collection of std::pair object and tuples are a generalization of pairs.
For completeness, if my understanding of your code purpose is correct, these are additions to your code for storing each tuple in a vector - declarations,
std::tuple<std::string, int> correct_word = {};
std::vector<std::tuple<std::string, int>> existing_words = {};
changes in the loop that saves existing words - here you want to add each word-value tuple to the vector,
if(word_input.length() == check_integrity)
{
// ...
correct_word = std::make_tuple(word_input, getScore(word_input));
existing_words.push_back(correct_word);
// ...
}
..and finally example of usage outside the construction loop:
for (size_t iv=0; iv<existing_words.size(); ++iv)
{
correct_word = existing_words[iv];
std::cout << std::get<0>(correct_word) << ": " << std::get<1>(correct_word) << std::endl;
}
std::cout << counter << std::endl;
The same code with a map would look like:
The only declaration would be a map from strings to values (instead of a tuple and vector of tuples),
std::map<std::string, int> existing_words = {};
In the construction loop you would be creating the map pair in a single line like this,
if(word_input.length() == check_integrity)
{
// ...
existing_words[word_input] = getScore(word_input);
// ...
}
While after constructing you would be accessing map elements using .first for the word and .second for the counter. Below is a printing example that also uses a for auto loop:
for (const auto& correct_word : existing_words)
std::cout << correct_word.first << ": " << correct_word.second << std::endl;
std::cout << counter << std::endl;
Notice that maps are by default alphabetically ordered, you can provide your own ordering rules and also use an unordered map if you don't want any ordering/sorting.

Why can I access C++ map elements with a for loop but not individually?

I'm having a bit of a problem with the code below.
#include <iostream>
#include <fstream>
#include <string>
#include <map>
std::map<std::string, int> m; //Dictionary map
int main() {
std::ifstream dictionaryFile("dictionary.txt");
std::string str;
int probability = -1;
//Read dictionary.txt and assign to map
while(std::getline(dictionaryFile, str)) {
if(str.find("#!comment:") == std::string::npos) { //Not a comment
m.insert(std::pair<std::string, int>(str, probability));
}
else {
probability++;
}
}
dictionaryFile.close();
//Iterate and print through map -- THIS WORKS
std::map<std::string, int>::iterator pos;
for(pos = m.begin(); pos != m.end(); ++pos) {
std::cout << "Key: " << pos->first << std::endl;
std::cout << "Value: " << pos->second << "\n" << std::endl;
}
//Is "very" in the map? -- THIS DOES NOT WORK
std::cout << m.find("very")->second << std::endl;
if(m.find("very") != m.end()) {
std::cout << "found it" << std::endl;
} else {
std::cout << "did not find it" << std::endl;
}
}
I read in the "dictionary.txt" file, and insert each word into a map. Either 1 or 2 is the value associated with that key, depending on the probability of the word.
I'm able to iterate through the map and print it's elements from within a for-loop, as shown. But I'm unable to access each element individually with m.find(), m.count(), or the [] operator. Each of those show as if the map is empty.
Do I have a piece of syntax wrong? Have I discovered a bug in std::map? Any help would be appreciated!
Here is dictionary.txt if you would like it.
Your file contains Windows CRLF line endings \r\n. These are automatically translated into \n with the default istream processing on Windows. However, you are on a Linux system that will be treating your \r character as nothing particularly special.
There are various ways around this. The simplest would be to not use such files as inputs on Linux. You can find answers elsewhere on this site for how to convert line-endings in the shell.
If you absolutely want your program to handle them, then you need to introduce some extra code. It can be as simple as checking the last character:
if (!str.empty() && str.back() == '\r')
str.pop_back();
For pre-C++11 standard library that doesn't have std::string::pop_back, you can just call str.erase(str.size()-1) instead.

C++ Usage of set, iterator, find line where duplicate was found

The program adds different strings to a set. The iterator checks the set for a certain string, what i want to achieve is to get the line where the iterator finds this certain string. Is it possible to get this with a set or do i have to create a vector? The reason i use sets is because i also want not to have duplicates in the end. It is a bit confusing i know, i hope you'll understand.
Edit: i want to get the line number of the original element already existing in the set, if a duplicate is found
#include <iostream>
#include <set>
#include <string>
#include <vector>
#include <atlstr.h>
#include <sstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
set<string> test;
set<string>::iterator it;
vector<int> crossproduct(9, 0);
for (int i = 0; i < 6; i++)
{
crossproduct[i] = i+1;
}
crossproduct[6] = 1;
crossproduct[7] = 2;
crossproduct[8] = 3;
for (int i = 0; i < 3; i++)
{
ostringstream cp; cp.precision(1); cp << fixed;
ostringstream cp1; cp1.precision(1); cp1 << fixed;
ostringstream cp2; cp2.precision(1); cp2 << fixed;
cp << crossproduct[i*3];
cp1 << crossproduct[i*3+1];
cp2 << crossproduct[i*3+2];
string cps(cp.str());
string cps1(cp1.str());
string cps2(cp2.str());
string cpstot = cps + " " + cps1 + " " + cps2;
cout << "cpstot: " << cpstot << endl;
it = test.find(cpstot);
if (it != test.end())
{
//Display here the line where "1 2 3" was found
cout << "i: " << i << endl;
}
test.insert(cpstot);
}
set<string>::iterator it2;
for (it2 = test.begin(); it2 != test.end(); ++it2)
{
cout << *it2 << endl;
}
cin.get();
return 0;
}
"Line number" is not very meaningful to a std::set<string>,
because as you add more strings to the set you may change the
order in which the existing strings are iterated through
(which is about as much of a "line number" as the set::set template
itself will give you).
Here's an alternative that may work better:
std::map<std::string, int> test.
The way you use this is you keep a "line counter" n somewhere.
Each time you need to put a new string cpstot in your set,
you have code like this:
std::map<std::string>::iterator it = test.find(cpstot);
if (it == test.end())
{
test[cpstot] = n;
// alternatively, test.insert(std::pair<std::string, int>(cpstot, n))
++n;
}
else
{
// this prints out the integer that was associated with cpstot in the map
std::cout << "i: " << it->second;
// Notice that we don't try to insert cpstot into the map in this case.
// It's already there, and we don't want to change its "line number",
// so there is nothing good we can accomplish by an insertion.
// It's a waste of effort to even try.
}
If you set n = 0 before you started putting any strings in test then
(and don't mess with the value of n in any other way)
then you will end up with strings at "line numbers" 0, 1, 2, etc.
in test and n will be the number of strings stored in test.
By the way, neither std::map<std::string, int>::iterator nor
std::set<std::string>::iterator is guaranteed to iterate through
the strings in the sequence in which they were first inserted.
Instead, what you'll get is the strings in whatever order the
template's comparison object puts the string values.
(I think by default you get them back in lexicographic order,
that is, "alphabetized".)
But when you store the original "line number" of each string in
std::map<std::string, int> test, when you are ready to
print out the list of strings you can copy the string-integer pairs
from test to a new object, std::map<int, std::string> output_sequence,
and now (assuming you do not override the default comparison object)
when you iterate through output_sequence you will get its
contents sorted by line number.
(You will then probably want to get the string
from the second field of the iterator.)

C++: boost range iterator pointing to wrong element

I ran into a strange problem. I have a vector<pair<bool, int>> from which I need to read (and possibly write) only the vector elements for which the boolean value of the pair is true. I am using boost range filter and reverse adaptors to do that.
However, I noticed that the order of the adaptors, ie whether I use reversed | filtered or filtered | reversed produces different results. In fact, when I use filtered | reversed then when I use an iterator to the transformed range to change the boolean value of the pair, then the iterator after the change points to a different vector element. This does not happen when I use reversed | filtered. Below is the code demonstrating the issue. Any ideas as to why this is happening are much appreciated!
#include <boost/range/adaptors.hpp>
#include <vector>
#include <utility>
#include <iostream>
using namespace boost::adaptors;
using container_type = std::vector<std::pair<bool,int>>;
struct to_include {
bool operator()(const std::pair<bool,int>& x) {
return x.first;
}
};
int main() {
container_type container;
/* element0: 1, 1 */
/* element1: 1, 2 */
/* element2: 1, 3 */
for(size_t i=0; i!=3; ++i) container.push_back(std::make_pair(true, i+1));
container_type container_cpy = container;
/* filter and then reverse */
auto fr = container | filtered(to_include()) | reversed;
auto fr_it1 = fr.begin();
auto fr_it2 = std::next(fr_it1);
fr_it2->first = false;
std::cout << "FILTER AND THEN REVERSE\n";
std::cout << fr_it2->first << " " << fr_it2->second << '\n'; /* prints (1,1) instead of (0,2) */
/* reverse and then filter */
auto rf = container_cpy | reversed | filtered(to_include());
auto rf_it1 = rf.begin();
auto rf_it2 = std::next(rf_it1);
rf_it2->first = false;
std::cout << "\nREVERSE AND THEN FILTER\n";
std::cout << rf_it2->first << " " << rf_it2->second << '\n'; /* prints (0,2) */
return 0;
}
This is a subtle issue. The point here is that after you modify the element pointed to by fr_it2, you also implicitly modify fr_it1 because fr is a lazy view on the original range. This means that the transformed filter needs to be recomputed. This is a very non-intuitive property, because for eager STL ranges, modifications through iterators don't modify the iterators themselves, but for lazy ranges this is no longer true!
In fact, if you print the entire fr and rf ranges using "fresh" iterators, you will see that their contents are in fact the same.
fr_it2->first = false;
for (auto e : fr) std::cout << e.first << e.second << ";"; // prints 13;11
...
rf_it2->first = false;
for (auto e : rf) std::cout << e.first << e.second << ";"; // prints 13;11
Live Example 1. So in fact the middle element is indeed deleted!
I think you should not modify elements through iterators into the adapated range, but rather through iterators into your primary container, like this:
auto fr_it1 = container.begin();
...
auto rf_it1 = container_cpy.begin();
Live Example 2.
If you do that, you get consistent results that show "0 2" for both approaches.