I have the following piece of code which helps me to write a bunch of values into a comma separated file format. My problem is, that I do not want a comma after the last element written to normcsv. How can I use beg in an If clause of the kind:
if(beg == penultimate element)
then.... bla bla...
Everything I tried out ended up with the iterator being mad invalid
ReadLine.erase(0,17);
int offsets[] = {8,8,8,8,8,8};
boost::offset_separator f(offsets, offsets+6);
boost::tokenizer<boost::offset_separator> RVBEARline(ReadLine,f);
boost::tokenizer<boost::offset_separator>::iterator beg;
for( beg=RVBEARline.begin(); beg!=RVBEARline.end();++beg )
{
copy=*beg;
boost::trim(copy);
if(copy.compare(0,1,".")==0)
{
copy.insert(0,"0");
}
normcsv << copy <<",";
}
Instead of printing the comma after the element except during the last iteration, print it before the element except during the first iteration. For that, you can use if(beg != RVBEARline.begin()).
An alternative to ruakh's "first plus rest" approach, you can do with one less local variable by using a loop-and-a-half construct:
{
auto it = x.begin(), end = x.end();
if (it != end)
{
for ( ; ; )
{
process(*it);
if (++it == end) break;
print_delimiter();
}
}
}
Here x.begin() and x.end() are only called once. There is one mandatory comparison per loop round, the minimum possible. The check for emptiness is hoisted outside.
Couldn't you just always remove the last character since you know it will be an extraneous comma?
Related
I'm currently working on a small program where I will count the amount of times a certain word is mentioned in a text. But I only want to count for the word when the previous element is a 10 digit number.
So what I'm trying is do is that I will check if the previous element of the iterator consist of a 10 digit number. But I don't know how to iterate to the previous element from the iterator.
QString input = ui->listinput->toPlainText();
QStringList inputlist = input.split(QRegExp("[\s\n\r " "]+"));
unsigned int boxCount(0);
for(QStringList::iterator it(inputlist.begin()); it != inputlist.end(); ++it){
if(!QString::compare(*it,box)) ++boxCount;
}
So I want the if statement to be something like this:
if(!QString::compare(*it,box) && *prev_it == 10 digits) ++boxCount;
Any help will be appreciated. Thanks!
You can obtain the previous iterator by doing:
if (it != inputlist.begin()) {
prev_it = it - 1
}
You will have to make an exception for the first element, since it has no previous element. Either check the range (like above) or start your for loop one element past the first (note the '+ 1'):
for (QStringList::iterator it(inputlist.begin() + 1); it != inputlist.end(); ++it) {
...
}
In the latter case, you must be sure that your list contains at least one element.
If you then want to check if the number is 10-digit (assuming decimal and integer) you can try the following:
bool ok = false;
long num = prev_it->toLong(&ok);
if (ok && num >= 1000000000) {
// do something
}
Note: I used the long type because I do not know the range of your numbers, but they seemed big.
Suppose I have a string foo and I want to search for the second period, if any.
I'm using this code:
std::size_t start = foo.find_first_of('.');
if (start != std::string::npos){
std::size_t next = foo.find_first_of('.', start + 1);
/*and so on*/
I'm wondering if this is well-defined if the first period is at the end of the string.
I think it is since start + 1 will be on the null-terminator, so I'm not in any danger of accessing any memory I shouldn't.
Am I correct?
If the first dot is at the end of the string, it's at index size() - 1.
So then start + 1 == size(), meaning that find_first_of will look in the interval [size(), size()). This is an empty interval, so no memory accesses will be made at all.
There may well not be a null-terminator at that point. (The standard does not guarantee it: c_str() is required to add one if necessary).
But your code is fine in any case. The behaviour on setting a pointer to point to 1-past-an-array is well-defined, so it's permissible to call the function with start + 1 is start is the last character in your string. Internally, a dereference of that pointer will not take place you're outside the region that find_first_of will search.
The C++ Standard does not impose any restriction on the value of the second parameter.
The function tries to calculate an actual position xpos the following way
pos <= xpos and xpos < size()
If it is unable to find such a velue it returns std::string::npos
For example
std::string s( "AB" );
auto pos = s.find_first_of( "A", std::string::npos );
if ( pos == std::string::npos ) std::cout << "Not found" << std::endl;
The output is
Not found
This question already has answers here:
How to remove certain characters from a string in C++?
(15 answers)
Closed 3 years ago.
I'm trying to remove special characters from a string using an isWordChar() method. However, I need to keep two special characters, " ' " and " - ", such as the apostrophe in "isn't" and the hyphens in mother-in-law. Here's what I'm trying to implement:
std::string WordCount::stripWord(std::string word) {
for(unsigned int i = 0; i < wrd.size(); ++i)
{
if( !isWordChar(wrd[i]) && (wrd[i]!=39 && wrd[i]!=45))
{
wrd.erase(wrd.begin()+i);
--i;
}
}
return wrd;
}
After adding the special cases in my boolean, I can't get seem to correctly add the exception. Any hints or advice? Thanks!
I would use the remove/erase idiom:
word.erase(std::remove_if(word.begin(),
word.end(),
[](char c) {
return !(isWordChar(c) || '-' == c || '\'' == c);
}), word.end());
The way you're erasing characters has complexity of approximately O(N * M) (where N is the original length of the string and M is the number of characters you remove). This has a complexity of approximately O(N), so if you're removing very many characters (or the string is very long) it's likely to give a substantial speed improvement.
If you care about why it's so much faster, it's because it works somewhat differently. To be specific, when you erase an element from the middle of a string, the erase function immediately copies all the letters after that to fill the hole where you erased the character. If you do this M times, all those characters get copied one for each character you remove.
When you use remove_if, it does something more like this:
template <class Iter, class F>
Iter remove_if(Iter b, iter e, F f)
auto dest = word.begin();
for (auto src=word.begin(); src != word.end(); ++src)
if (!f(*src))
*dst++ = *src;
++src;
}
return dst;
}
This way, each character that's retained is only copied once, rather than being copied every time you remove one character from the string. Then when you do the final erase, it just removes characters from the end of the string, so it's basically just adjusting the length of the string downward.
Your logic is incorrect. It should be: !isWordChar(wrd[i]) && wrd[i] != 39 && wrd[i] != 45. Read as: If the character isn't a word character, and it's not an apostrophe, and it's not a hyphen, do whatever is in the if-statement.
bool e_broj(const string &s){
string::const_iterator it = s.begin();
while(it != s.end() && isdigit(*it)){
++it;
}
return !s.empty() && it == s.end();
}
I have this function to check if a string is a number. I found this snippet online and I would like to understand how it works.
// this declares it as the beginning of the string (iterator)
string::const_iterator it = s.begin();
// this checks until the end of the string and
// checks if each character of the iterator is a digit?
while(it != s.end() && isdigit(*it)){
// this line increases the iterator for next
// character after checking the previous character?
++it;
// this line returns true (is number) if the iterator
// came to the end of the string and the string is empty?
return !s.empty() && it == s.end();
Your understanding is almost right. The only mistake was at the end:
// this line returns true (is number) if the iterator
// came to the end of the string and the string is empty?
return !s.empty() && it == s.end();
This should say "and the string is not empty", because the expression is !s.empty(), rather than just s.empty().
You may just have worded this funny, but to be clear, the condition on the while loop will keep the iterator moving through the string while it's not at the end and while the characters are still digits.
Your terminology with regards to the iterator makes me think you don't quite understand fully what it's doing. You can think of an iterator as being like a pointer (actually, pointers are iterators, but not necessarily vice-versa). The first line gives you an iterator that "points at" the first character in the string. Doing it++ moves the iterator to the next character. s.end() gives an iterator that points one past the end of the string (this is a valid iterator). *it gives you the character that the iterator is "pointing at".
The while loop stops at the of string OR when a non-digit shows up.
So, if we did not advance all the way to the end (it != s.end()), then the string has non-digit and therefore is not a number.
Empty string is a special case: it has no non-digits but it's not a number either.
Don't think its necessary to read part one, but I'l include the link just incase:
why does std::search need forward iters
.....almost there with iterator catagories(I think) ..I looked around to find an easy all-in-1 table, that shows the functionality available from the various types of iterators ..couldn't find one so I'v tried to expand stroustrup's table to include things like: the ability to pass over a range more than once etc...let me know if I'v missed or misunderstood anything? ..or if there's a better table kicking about
*1++ must be (de)referenced between incrementions
*n++ can be incremented more than once without being (de)referenced
*n_save range can be passed over more than once and also saved/copied
------------------------------------------------------------------------------
- Iterator Operations and Categories
------------------------------------------------------------------------------
Category: output input forward bidirectional random-access
Abbreviation: Out In For Bi Ran
------------------------------------------------------------------------------
Read(*1++): =*p
Read(*n++): =*p =*p =*p
Read(*n_save): =*p =*p =*p
Write(*1++): *p=
Write(*n++): *p= *p= *p=
Write(*n_save): *p= *p= *p=
Access: -> -> -> ->[]
Iteration: ++ ++ ++ ++-- ++ -- + - += -=
Comparison: == != == != == != == != < > >= <=
------------------------------------------------------------------------------
Write(*n_save) ...wasn't sure if copying/saving an iter is read or write ..so I added it to both? ..Im guessing if you can read-pass a range more than once..you might also want to write-pass a range more than once?
I now understand why std::search needs forward iterators, but unsure why it needs 4 ..would 2 For & 2 In suffice?
while ( begin != end ) {
if( begin2 == end2 ) { return found ; }
}
..is it because end and end2 are refd more than once( every time the while loops)..?
template <class For, class In>
For search( For begin, In end, For begin2, In end2 )
{
For found ;
For pattern_begin = begin2 ; //refd
int flag = 0 ;
// search content for pattern
while ( begin != end ) { //refd
if ( *begin != *begin2 ) { //de-refd
begin2 = pattern_begin ; //store/copy
flag = 0 ;
begin++ ; //inc
} else {
if ( flag == 0 ) {
found = begin ;
flag = 1 ;
}
begin++ ;
begin2++ ;
}
if( begin2 == end2 ) { return found ; } //refd
}
return begin ;
}
I think you've pulled the "must be incremented between dereferencing" out of thin air.
Input and output operator implement those, so that they could be used by a function that doesn't expect them in particular, but essentially incrementing may well be a no-op with them.
That search function needs four iterators, because otherwise there would simply be no way to tell where either range ends. An iterator by itself does not (necessarily) know whether it is at the end of the range or not.
A range in SC++L is represented by a pair of iterators of the same type. Technically the algorithms could accept iterators of different type for a single range, but that would hardly have any practical use and just make the code more error-prone. As it is, at least one kind of errors can be detected at compile-time:
void foo(container& a, const container& b, const container& c) {
std::search(a.begin(), b.end(), c.begin(), c.end());
}
The error here is passing iterators into different containers for the first two arguments. But in this case this would be caught at compile-time, because fortunately a and b happen to have different constness, so a.begin() returns container::iterator and b.end() returns a different type container::const_iterator. If all four arguments were allowed to be of different types, then this error will lead to undefined behavior at runtime.