How std::find_last_of actually works? - c++

string s = "I Like C++ Tutorial";
cout << s.find_last_of("Like");
I know that find_last_of returns the last character that matches, however, it returns 16, which is the position of the letter i in Tutorial, But I'm confused because I'm searching for the last position of Like not i, I tried to remove i from the string. It returns 5 as I expected. But the question is why did it return 16?

find_last_of finds the last character equal to one of characters in the given character sequence.
The character sequence is "Like". The last L is at position 3, the last i is at position 16, the last k is at position 4 and the the last e is at position 5. So it returned the 16, the greatest of these values.
If the character sequence was "like" instead of "Like", it would have returned 18 because the last l is at position 18.
In case no letter in the character sequence that matches any letter in the string, npos is returned.

std::find_last_of
Finds the last character equal to one of characters in str
this means when searching the string "I Like C++ Tutorial" for the string "Like" the last character that apears in both strings is "i" wich is at position 16.
when searching for a complete string use std::find
std::string s("I Like C++ Tutorial");
std::cout << s.find("Like"); // prints 2
if you want to find the last occurence of the string use std::rfind
std::string s("I Like C++ Tutorial Like");
std::cout << s.rfind("Like"); // prints 20
to get the position of the last character in the last match you just have to add the length of the string:
std::string s("I Like C++ Tutorial Like");
std::string s2("Like");
std::cout << s.rfind(s2) + s2.length(); // prints 24

Related

Iterations of while loop returns strange values

I have two questions:
Assume the characters entered by the user in input are all contained in alphabet:
If my input starts with "A", the first character in my output is "A", but if I start with any other character in alphabet, the output is the original character shifted to the right by 3. If my input starts with "A", why does my output also start at "A" and not at "D"?
If my input is a string that has spaces (e.g. "Stack Overflow"), why is the first word the only component of my output? (How is the computer interpreting this?) I understand C++ considers new lines, spaces, and tabs to be whitespace, but I thought if the space was in a string, it would be treated as a character. How can I modify my code so the space and the rest of my input is included (preferably shifted) in my output?
using namespace std;
string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ##$%^&*()"; //a 62 character string
string input, output;
int shift = 3, index = 0;
cin >> input;
while(index < input.length()){
if(alphabet.find(input[index]) != NULL){
output += alphabet[(alphabet.find(input[index]) + shift) % 62];
}
index++;
}
If my input starts with "A", the first character in my output is "A", but if I start with any other character in alphabet, the output is the original character shifted to the right by 3. If my input starts with "A", why does my output also start at "A" and not at "D"?
It doesn't. It skips the "A" and does not add it to the output at all!
This is because std::string::find() DOES NOT return a pointer, it returns an index. If it does not find a match, it returns std::string::npos (-1). Comparing NULL to an index treats the NULL as index 0. So, when find() does find "A", it returns 0, which you then compare as equal to NULL (0) and thus skip adding "D" to the output. All of the other input characters make find() return indexes other than 0, so they don't compare equal to NULL and so you shift all of them (including ones that cause find() to return npos, you shift all of those to index 2).
If my input is a string that has spaces (e.g. "Stack Overflow"), why is the first word the only component of my output? (How is the computer interpreting this?) I understand C++ considers new lines, spaces, and tabs to be whitespace, but I thought if the space was in a string, it would be treated as a character. How can I modify my code so the space and the rest of my input is included (preferably shifted) in my output?
operator>> reads whitespace-delimited words. It first skips leading whitespace (unless std::noskipws is used), and then it reads until it encounters whitespace. To read a string with spaces in it, use std::getline() instead.
With that said, try this instead:
using namespace std;
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ##$%^&*()"; //a 62 character string
string input, output;
const int shift = 3;
getline(cin, input);
for (string::size_type index = 0; index < input.length(); ++index) {
string::size_type found_index = alphabet.find(input[index]);
if (found_index != string::npos) {
output += alphabet[(found_index + shift) % alphabet.size()];
}
}
/*
Or, using C++11 or later:
for (char c : input) {
auto found_index = alphabet.find(c);
... (same as above) ...
}
*/
Also, how does one format variables when asking questions on StackOverflow so that they're in little code blocks within writing a question? I see that on other people's posts, but I don't know how to do it, and it makes things far more readable.
Blocks of code can be indented by 4 spaces. The toolbar on StackOverflow's editor has a button for formatting code blocks. Just select the code and press the button.
Code inline of other text can be wrapped in `` quotes.
Click on the ? button on the right side of the editor's toolbar to see the supported formatting markup.

Why is the length of a string off by one on the first read of a file?

I am perplexed with the way my program is performing. I am looping the following process:
1) take the name of a course from an input file
2) output the length of the name of the course
The problem is that the first value is always one less than the actual value of the string.
My first string contains 13 characters (including the colon), but nameOfClass.length() returns 12. The next string, the character count is 16 and indeed, nameOfClass.length() returns 16.
Every value after that also returns the expected value, it is only the first that returns the expected value minus 1.
Here's the (reduced) code:
std::ifstream inf("courseNames.txt");
int numberOfClasses = 10;
string nameOfClass;
for (int i = 0; i < numberOfClasses; i++) {
std::getline(inf, nameOfClass,':');
std::cout << nameOfClass.length() << "\n";
}
The file looks like this (courseNames.txt):
Pre-Calculus:
Public-Speaking:
English I:
Calculus I:
...etc. (6 more classes)
This is what I get:
12
16
10
11
Can anyone explain this behavior of the .length() function?
You have a problem, but you have the wrong conclusion. std::getline reads but doesn't output the delimiter, and so the first result is indeed 12.
It also doesn't output the delimiter for any subsequent lines, so why is there always one more? Well, look what is after that :. That's right, a new line!
Pre-Calculus:
^ a new line
So your nameOfClass variable, except for the first string, always stores an extra newline before the other characters.
The fix is easy enough, just ignore the newline after reading the string.
inf.ignore(); // ignore one character
So, not the first result was wrong, it was the only one right :)

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

How to fetch the string using the substr with garbage characters?

I have this string, if
size_t pos;
pos = eNBSWVerTmp.find("MAC");
When I print out the pos, pos 4294967295.
Is there a way I can fetch the string start from 1103?
♦ƒ+Hm.0_MAC_1103_064_00, 21.06.1ÿs7÷l ↕
I think garbage chars caused the pos out of range. Thanks in advance.
Do this:
std::string test("MAC");
std::copy(test.begin(), test.end(), std::ostream_iterator<int>(std::cout," "));
std::cout << "\n";
std::copy(eNBSWVerTmp.begin(), eNBSWVerTmp.end(), std::ostream_iterator<int>(std::cout," "));
std::cout << "\n";
Now see if the numbers in the top line match a similar sequence of numbers in the bottom line.
I am betting you will not find a match. But you may be able to work out why.
If you start by
const size_t pos = eNBSWVerTmp.find("MAC");
you know that pos indicates where M in MAC can be found (or is std::string::npos if not found).
To get some substring starting, say, 4 bytes forward from pos, you can do
std::string substring;
if (pos != std::string::npos)
substring = eNBSWVerTmp.substr(pos + 4, number_of_bytes);
to get the number_of_bytes you want.
The position 4294967295 isn't a garbage number, it's consistent with what happens if you store a negative number in an unsigned type such as size_t. This would be returned by find if the substring MAC can't be found. So it probably means there's an invisible character inside the substring MAC. You might try iterating through the string in an encoding-specific way, and appending characters to a new string (or std::vector<char>) only if they're expected characters (i.e. letters, digits, etc.), then finding MAC within that.

Is the integer n in the string s? Is 4 in Ab56c4D? (C++)

Is there a standard function which will return a bool for this?
I'm writing a program that plays the game of life and the user enters two strings, S23 and B3 are examples. In my main loop I just want to check if an integer (the number of living surround cells) is in one of the strings.
Thanks for your help with this question. ;)
http://www.cplusplus.com/reference/string/string/find/
Searches the string for the content specified in either str, s or c, and returns the position of the first occurrence in the string.
Return Value:
The position of the first occurrence in the string of the searched content.
If the content is not found, the member value npos is returned.
First you need to get a string version of the integer value, then you can try to find it in the other string:
std::ostringstream oss;
oss << some_integer;
if (some_string.find(oss.str()) != std::string::npos)
// match...
Loop through the characters in the string and if the character ( (int)cur_char) ) is between 48 and 57 return true.