I'm not sure about find_last_of(

Hi! I tried to print words which end with "aty" and to count them using the find_last_of function. As you can see, there are four such words, but the execution result is


pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysoki baly
Words ending with 'aty':
pryvitaty
zdaty
their number is 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <string>
#include <vector>
#include<sstream>
using namespace std;
vector<string> Split(string strToSplit, char delimiter)
{
	stringstream ss(strToSplit);
	string item;
	vector<string> splittedStrings;
	while (getline(ss, item, delimiter))
	{
		splittedStrings.push_back(item);
	}
	return splittedStrings;
}
int main()
{
const string text = " pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysiki baly ";
const string end = "aty";
vector<string> words = Split(text, ' ');
cout<<"pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysoki baly"<<endl;
int n = 0;
cout<<"Words ending with 'aty':"<<endl;
for(int i=0;i<words.size();i++) {
	if(words[i].find_last_of(end,2)==2){
	cout<<words[i]<<endl;
	n++;
}
} 
cout<<"their number is "<<n;
return 0;
}
http://www.cplusplus.com/reference/string/string/find_last_of/ writes:
Searches the string for the last character that matches any of the characters specified in its arguments.

When pos is specified, the search only includes characters at or before position pos, ignoring any possible occurrences after pos.


You have pos=2. Therefore, you are looking at words:
pry z nov rok i pob zda vsi rob i otr vys bal

You accept only position 2 matches (==2).
Which words have 'a' or 't' or 'y' as third character?
pry zda 
  ^   ^


Two errors:
1. You are looking from the wrong part of the words
2. find_last_of does not look for substring

1
2
auto tail = std::max( 0, static_cast<int>(words[i].size()) - 3 );
if ( words[i].substr( tail ) == end ) {
Thank you very much, Kakiverto! Now I understand my mistakes)
Thank you very much, Keskiverto! Now I understand it better)
Use .rfind():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

vector<string> Split(const string& strToSplit, char delimiter)
{
	stringstream ss(strToSplit);
	vector<string> splittedStrings;

	for (string item; getline(ss, item, delimiter); splittedStrings.push_back(item));

	return splittedStrings;
}

int main()
{
	const string text {" pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysiki baly "};
	const string end {"aty"};
	const vector<string> words {Split(text, ' ')};

	cout << '\n' << text << "\nWords ending with '" << end << "'\n";

	int n {};

	for (const auto& w : words)
		if (w.size() >= end.size())
			if (const auto strt {w.size() - end.size()};  w.rfind(end, strt) == strt) {
				cout << w << '\n';
				++n;
			}

	cout << "their number is " << n;
}


or for C++20:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
	const string text {" pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysiki baly "};
	const string end {"aty"};
	const vector<string> words {Split(text, ' ')};

	cout << '\n' << text << "\nWords ending with '" << end << "'\n";

	int n {};

	for (const auto& w : words)
		if (const auto strt {ssize(w) - ssize(end)}; (strt >= 0) && (w.rfind(end, strt) == strt)) {
			cout << w << '\n';
			++n;
		}

	cout << "their number is " << n;
}


Or alternatively, use .ends_with():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
	const string text {" pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysiki baly "};
	const string end {"aty"};
	const vector<string> words {Split(text, ' ')};

	cout << '\n' << text << "\nWords ending with '" << end << "'\n";

	int n {};

	for (const auto& w : words)
		if (w.ends_with(end)) {
			cout << w << '\n';
			++n;
		}

	cout << "their number is " << n;
}




pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysoki baly
Words ending with 'aty':
pryvitaty
pobazhaty
zdaty
otrymaty
their number is 4

Last edited on
Hello crueltyfree,

If you are writing your code for the compiler you have failed because there is to much white space in the code.

The compiler will ignore any white space, including blank lines, and comments when it creates its object code.

If you want someone to read you code, and you do, consider this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <string>
#include <vector>
#include<sstream>

using namespace std;

vector<string> Split(string strToSplit, char delimiter)
{
    stringstream ss(strToSplit);
    string item;
    vector<string> splittedStrings;

    while (getline(ss, item, delimiter))
    {
        splittedStrings.push_back(item);
    }

    return splittedStrings;
}
int main()
{
    const string text = " pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysiki baly ";
    const string end = "aty";

    vector<string> words = Split(text, ' ');

    cout << "\n pryvitaty z novym rokom i pobazhaty zdaty vsi roboty i otrymaty vysoki baly" << endl;

    int wordCount = 0;  // <--- A much better name than "n" which has no meaning.

    cout << "\n Words ending with 'aty':\n";

    for (size_t idx{}; idx < words.size(); idx++)
    {
        if (words[idx].find(end) != std::string::npos)
        {
            cout << "  " << words[idx] << '\n';

            wordCount++;
        }
    }

    cout << "\n Their number is " << wordCount;

    return 0;  // <--- Not required, but makes a good break point.

}

Line 30 as an example use a good name over a single letter variable.

I revised the for loop a bit. The ".size()" function returns a "size_t" variable type, so it is best if the loop iterator matches, avoids the warning of a type mismatch.

The if state makes use of the find function, which is better than the way you are trying to use "find_last_of" which is checking from right to left.

Andy
@Andy, that code will also find words that contain 'aty' anywhere - even at the start. Not just at the end as required. See my code above.

@seeplus,

Good point. I did not think about that.

I will try the "rfind".

Andy
Topic archived. No new replies allowed.