I am reading strings with the following syntax:
string example {"firstList:[element1:value1,element2:value2];secondList:[elementA:valueA,elementB:valueB]"};
Since a real list can have hundreds of elements, and I need only read operations (checking if value1 == "something"
or if elementA
exists), I implemented a std::string::iterator
based function to find a list inside a given string. Here is a simplified version:
bool findList(
const std::string &input,
const std::string &listName,
std::string::iterator globalStart,
std::string::iterator globalEnd,
std::string::iterator &listStart,
std::string::iterator &listEnd
)
{
if (input.empty() || listName.empty()) return false;
size_t inicio = input.find(listName);
if (inicio == string::npos) return false;
size_t fin = input.find("]", inicio);
if (fin == string::npos) return false;
listStart = globalStart + inicio + listName.length() + 2;
listEnd = globalStart + fin;
if (listEnd >= globalEnd) return false;
string::iterator badList = std::find(listStart, listEnd, ';');
if (badList != listEnd) return false;
return true;
}
The function works, but I have to pass the string input
, input.begin()
, and input.end()
to assign values for the list iterators. Is there another option to assign the input.begin()
to listStart
(and the same for listEnd
)?
Writing:
listStart = input.begin() + inicio + listName.length() + 2;
listEnd = input.begin() + fin;
yields a compiler error for trying to assign a const iterator to a non-const iterator:
error: no match for ‘operator=’ (operand types are ‘std::__cxx11::basic_string<char>::iterator {aka __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >}’ and ‘__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >’)
listStart = input.begin() + inicio + listName.length() + 2;
I am aware that passing the input
only as std::string &input
solves the problem, but I would like to keep the checks that const
entails.
Here is a minimal example:
#include <iostream>
#include <string>
#include <algorithm>
#include <assert.h>
using std::cout;
using std::endl;
using std::string;
using std::size_t;
bool findList(
const std::string &input,
const std::string &listName,
std::string::iterator globalStart,
std::string::iterator globalEnd,
std::string::iterator &listStart,
std::string::iterator &listEnd
)
{
if (input.empty() || listName.empty()) return false;
size_t inicio = input.find(listName);
if (inicio == string::npos) return false;
size_t fin = input.find("]", inicio);
if (fin == string::npos) return false;
listStart = globalStart + inicio + listName.length() + 2;
listEnd = globalStart + fin;
if (listEnd >= globalEnd) return false;
string::iterator badList = std::find(listStart, listEnd, ';');
if (badList != listEnd) return false;
return true;
}
int main() {
string example {"firstList:[element1:value1,element2:value2];secondList:[elementA:valueA,elementB:valueB]"};
string::iterator listStart, listEnd;
bool answer = false;
// Test the findList function
answer = findList(example, "firstList", example.begin(), example.end(), listStart, listEnd);
assert(answer == true);
assert(string(listStart, listEnd) == "element1:value1,element2:value2");
cout << "Test firstList passed" << endl;
answer = findList(example, "secondList", example.begin(), example.end(), listStart, listEnd);
assert(answer == true);
assert(string(listStart, listEnd) == "elementA:valueA,elementB:valueB");
cout << "Test secondList passed" << endl;
answer = findList(example, "thirdList", example.begin(), example.end(), listStart, listEnd);
assert(answer == false);
assert(string(listStart, listEnd) == "elementA:valueA,elementB:valueB"); // iterators remain unchanged
cout << "Test thirdList passed" << endl;
return 0;
}
*This is my first question, please feel free to point out any improvement I could make to the post.
const std::string::iterator
means "iterator for a string, through which the string can be changed; the iterator can't be pointed anywhere else."
std::string::const_iterator
means "iterator for a string, through which the string cannot be changed; the iterator can be pointed somewhere else."
It looks like you are confusing these two. input.begin()
returns a const_iterator
when input
is const
, and you can't assign a const_iterator
to an iterator
-- that would break const-correctness.
All of your iterators in this function should be const_iterator
. Change your function signature to:
bool findList(
const std::string &input,
const std::string &listName,
std::string::const_iterator globalStart,
std::string::const_iterator globalEnd,
std::string::const_iterator &listStart,
std::string::const_iterator &listEnd
) {
// ...
}
The caller should then use str.cbegin()
and str.cend()
. Likewise, listStart
and listEnd
in main()
should be changed to be const_iterator
.