C++ substring why does it do that? - c++

I am trying to reverse order of a string 5 characters from end of string to beginning For example, if the input was "11111000002222233333", I want output to be "33333222220000011111"
string reverse(string str)
{
string tmp = "";
for(int i = str.length(); i >= 5; i = i - 5)
{
tmp.append(str.substr(i - 5, i));
}
return tmp;
};
lets just say that my input was "1000001010000000000010100" but it returns "101000000010100000000000010100010100000010000"

According to documentation:
Returns a substring [pos, pos+count). If the requested substring
extends past the end of the string, or if count == npos, the returned
substring is [pos, size()).
std::string substr(size_type pos = 0, size_type count = npos) const;
Your mistake is that you treat substr() second parameter as position index.
But it's substring length, not end position.
Quick fix is tmp.append(str.substr(i - 5, 5));

Related

Initial Check to see if a Substring is within range

I am in the beginnings of learning C++ and I am wondering if there is a way to assert that a substring can be created from a String, given a range. My String will vary in size each iteration. I am trying to create six substrings from that original String. With this variation in size, I am sometimes trying to access indexes of the String that do not exist for that particular iteration.
For example, if my String in iteration 1 is 11 characters
My first substring is from 3 characters - valid
My second substring is the next 3 characters - valid
My third substring is the next 5 characters - valid
My fourth substring is the next 4 characters - not valid - crashes program
My fifth substring - not valid, out of range
My sixth substring - not valid, out of range
I am wondering if there is a small check I can do to assert the length is valid. It's worth noting, I suppose, that I have not set any default values to these substrings. They are declared as:
string subS1
string subS2
string subS3
...
...
string subS6
Would setting all 6 substrings to null upon declaration alleviate this issue and for any valid substring, the value will just be overwritten?
Thanks in advance
subS1 = str.substr(0, 3); // Could be valid range
subS2 = str.substr(3, 3); // Could be valid range
subS3 = str.substr(6, 5); // Could be valid range
subS4 = str.substr(11, 4); // Could be valid range
subS5 = str.substr(15, 4); // Could be valid range
subS6 = str.substr(19); // from the nineteenth character to the end
Algorithm--->
step 1: Get the length of string in current iteration in variable size.
step 2: Write this code in itertaion.
int i=0;
i= str.substr(start,end).length();
if( i>size) then,
std::cout<<"index exceeded";
Either check the size of str before extracting the string, or rely on std::string::substr's len parameter:
Number of characters to include in the substring (if the string is
shorter, as many characters as possible are used). A value of
string::npos indicates all characters until the end of the string.
Example:
#include <iostream>
#include <string>
int main ()
{
std::string str="Alexander the Great";
std::string str2 = str.substr (16, 25);
std::cout << str2 << '\n'; // eat
return 0;
}
It won't crash, it will just use as many characters as possible.
This however:
std::string str2 = str.substr (20, 25);
should crash, so do it like this in this case:
std::string str2 = ""; // initialise to empty string, that is the NULL you are saying I guess
if(str.size() > 20)
str2 = str.substr (20, 25);
// 'str2' will be an empty string

Split the string in C++ using command std::string::substr

I'm able to get the first half of string:
insert1 = tCreatureOne.substr(0, (tCreatureOne.length) / 2
I don't know how to get the second half of the string
insert2 = tCreatureOne.substr((tCreatureOne.length) / 2), ?????)
Here is my code.
// Insert creature two in to the
//middle of creature one.Science!
// Hamster and Emu make a HamEmuster
std::string PerformScience(std::string tCreatureOne, std::string tCreatureTwo)
{
std::string insert1;
std::string insert2;
std::string insert3;
// first half : 0 to middle
insert1 = tCreatureOne.substr(0, (tCreatureOne.length) / 2);
// last half: from middle to the end
insert2 = tCreatureOne.substr((tCreatureOne.length) / 2), tCreatureOne.length);
insert3 = insert1 + tCreatureTwo + insert2;
return insert3;
Probably the most important developer skill is knowing how to do online research. A google search for "c++ substr" reveals this as the top result: http://www.cplusplus.com/reference/string/string/substr/
In the section describing parameters, len is described as follows:
Number of characters to include in the substring (if the string is shorter, as many characters as possible are used).
A value of string::npos indicates all characters until the end of the string.
So you could write:
insert2 = tCreatureOne.substr(tCreatureOne.length() / 2), std::string::npos);
However, note that substr is declared as follows:
string substr (size_t pos = 0, size_t len = npos) const;
Meaning len quite conveniently defaults to npos.
Therefore you could more simply write:
insert2 = tCreatureOne.substr(tCreatureOne.length() / 2));
However, even if substr didn't have such a convenient means of specifying 'the rest of the string', you could still have quite easily calculated it as follows:
int totalLength = tCreatureOne.length();
int firstLength = totalLength / 2;
int remainderLength = totalLength - firstLength;
//So...
insert2 = tCreatureOne.substr(tCreatureOne.length() / 2), remainderLength);
πάντα ῥεῖ is correct in their comment - to retrieve the second half of your string, you don't need to specify a second parameter (the end of the string):
insert2 = tCreatureOne.substr(tCreatureOne.length() / 2);
The line above will work perfectly fine. Also, since you're using std::string, remember to add the parentheses to the length() call.

Removing consecutive duplicate characters from a std::string

I'm currently trying to remove duplicate characters. For example:
maaaaaaa becomes ma
aaaaassssdddddd becomes asd
I have written the following piece of code:
string.erase(remove(string.find_first_of(string[i]) + 1, string.end(), string[i]), string.end());
but apparently std::string returns a pointer to the last + 1 character of the string, rather than the size, any ideas how I could remove string[i] from my string starting from the position next to that char?
string.find_first_of returns an integer position (and string::npos if not found). This is not compatible withstd::remove, which expects iterators. You can convert from a position to an iterator by adding the position to the begin iterator.
char to_remove = string[i];
auto beg = string.begin() + string.find_first_of(to_remove) + 1;
auto new_end = std::remove(beg, string.end(), to_remove);
string.erase(new_end, string.end());

C++: Find method

so if i were to enter patricia(don't worry im converting it toupper) that string would be loaded into my vector.
My question is about the find functions. i am counting down characters correct? so if i were to enter patricia and j would be on ABBOT, PATRICIA the value in comma would be 5. Ok im good so far, but what happens in my found variable?
bool NameSearch::findFirstNames(vector<string> &vsFirst, string name)
{
int j = 0;
bool bName = false;
vsFirst.clear();
while(j < total)
{
int comma;
comma = names[j].find(',');
//Confused here
int found = names[j].find(name, comma);
if(found > -1)
{
vsFirst.push_back(names[j]);
bName = true;
}
j++;
}
return bName;
}
The if (found > -1) test probably works on your platform but is technically dubious.
The return type of std::string::find() is std::string::size_type, and if the substring you're searching is not found, the returned value is std::string::npos (on the other hand, if the substring is found, the returned value is the character index of its first occurrence).
Now the std::string::npos value happens to be the greatest possible value of type std::string::size_type, and if that is unsigned int on your implementation, that means the comparison with the signed int -1 will yield true.
However, no assumptions can be made in general on the type of std::string::size_type Thus, I suggest to rewrite the test as:
if (found != std::string::npos)
{
...
}
This is misleading code. std::string::find() returns a size_t, not an int.
int comma;
comma = names[j].find(',');
This is misleading code. When std::string::find() fails, it returns std::string::npos, not -1. In your environment, it's equivalent to -1 by coincidence.
if(found > -1)
The if statement is effectively trying to check "if a result was found" by making sure it isn't std::string::npos.
There are two other answers, that point out what is wrong with this code, but I feel like none of them explains to you, what the author was doing, and that's the explanation you want. :)
Let's look at the following snippet first.
int comma;
comma = names[j].find(',');
As pointed out, it should be rewritten as:
size_t comma;
comma = names[j].find(',');
There are 4 overloads of the find method in the std::string
The code above uses this one:
size_t find (char c, size_t pos = 0) const;
It returns the index, at which the character passed as the first argument (in your case it's ',') appears in the string or std::string::npos if that character isn't found. Apparently the author is sure the ',' character must be present in the string names[j] and doesn't check the result.
In the line:
int found = names[j].find(name, comma);
which again should be rewritten as:
size_t found = names[j].find(name, comma);
the following overload of the find method is used:
size_t find (const string& str, size_t pos = 0) const;
This one searches the string names[j] for the first occurrence of the string passed as the first argument (in your case name) and returns the index at which the match starts if there is a match or std::string::npos otherwise.
As you can see, both mentioned overloads of the find method have a second parameter with default value of 0. This second parameter allows a user to specify, at what index to start the search in the searched string (in your case names[j])
The call:
comma = names[j].find(',');
is equivalent to the call:
comma = names[j].find(',', 0);
and it means: look for the character ',' int the string names[j] starting from the beginning and return the index of the first occurrence of that character or std::string::npos, if there is no such character in that string.
The call:
size_t found = names[j].find(name, comma);
means: look for the substring equal to name in the string names[j], but start from the position where the comma was found and return the index of the first occurrence of that substring or std::string::npos if there is no such substring in that string, after the comma.
Maybe comma_position instead of comma would have been a better name for the variable.

middle function

I need a function middle that accepts a string and returns the middle character if there are an odd number of characters and the two middle characters if there are a even number of characters in the string in C++ for a program I am writing unfortunately I cannot find anything pre-made for an example thats in c++
std::string middleCharacters(const std::string &str)
{
if (str.length() <= 0) return ""; // For an empty string, return an empty string (customize this as desired)
return str.substr((str.length() - 1) / 2, 2 - str.length() % 2);
}
For proof that this works: http://ideone.com/vId2l