Finding a substring of multiple occurences in a string [C++] - string

is there any STL algorithm or a standard way of finding how many occurences of particular substring are there in a string? For example in string:
'How do you do at ou'
the string "ou" appears twice. I tried some STL algorithms with and without predicates but what I found is that those algorithms from STL want to compare components of string which in my case is char but cannot? compare substrings.
I come up with something like this:
str - string
obj - substring we're looking for
std::string::size_type count_subs(const std::string& str, const std::string& obj)
{
std::string::const_iterator beg = str.begin();
std::string::const_iterator end = str.end();
std::string::size_type count = 0;
while ((beg + (obj.size() - 1)) != end)
{
std::string tmp(beg, beg + obj.size());
if (tmp == obj)
{
++count;
}
++beg;
}
return count;
}
thank you.

#include <string>
#include <iostream>
int Count( const std::string & str,
const std::string & obj ) {
int n = 0;
std::string ::size_type pos = 0;
while( (pos = obj.find( str, pos ))
!= std::string::npos ) {
n++;
pos += str.size();
}
return n;
}
int main() {
std::string s = "How do you do at ou";
int n = Count( "ou", s );
std::cout << n << std::endl;
}

Related

Beginners sincerely ask for advice about string

What the class describes is about "reversing a string", which is correct and usable from the Leetcode website. Today, I want to present "reversing a string" by inputting a value by myself (such as the int main() part below), but I still can't execute it after thinking for a long time. Beginners sincerely ask for advice, maybe you can also attach your writing so that I can learn, thank you.
#include <iostream>
#include <string>
using namespace std;
class Solution
{
public:
string reverseWords(string s)
{
if (s.size() == 0)
{
return s;
}
int front = 0, back = 0;
for (int i = 0; i < s.size() - 1; i++)
{
if (s[i] != ' ')
{
back++;
}
else
{
reverse(s.begin() + front, s.begin() + back);
front = back + 1;
back = front;
}
}
back++;
reverse(s.begin() + front, s.begin() + back);
return s;
}
};
int main()
{
Solution word01;
string s1= "Hello caterpillar";
word01 s1;
cout << s1.reverseWords();
}
Your code is pretty good, however we just want to reverse the words not the chars, for that we can use a while loop.
Similarly using two pointers, this'd pass just fine:
// The following block might trivially improve the exec time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <string>
#include <algorithm>
static const struct Solution {
using ValueType = std::uint_fast16_t;
std::string reverseWords(std::string s) {
std::reverse(std::begin(s), std::end(s));
ValueType len = std::size(s);
ValueType index = 0;
for (auto left = 0; left < len; ++left) {
if (s[left] != ' ') {
if (index) {
s[index++] = ' ';
}
ValueType right = left;
while (right < len && s[right] != ' ') {
s[index++] = s[right++];
}
std::reverse(std::begin(s) + index - (right - left), std::begin(s) + index);
left = right;
}
}
s.erase(std::begin(s) + index, std::end(s));
return s;
}
};
Here is LeetCode's solution with comments:
class Solution {
public:
string reverseWords(string s) {
// reverse the whole string
reverse(s.begin(), s.end());
int n = s.size();
int idx = 0;
for (int start = 0; start < n; ++start) {
if (s[start] != ' ') {
// go to the beginning of the word
if (idx != 0) s[idx++] = ' ';
// go to the end of the word
int end = start;
while (end < n && s[end] != ' ') s[idx++] = s[end++];
// reverse the word
reverse(s.begin() + idx - (end - start), s.begin() + idx);
// move to the next word
start = end;
}
}
s.erase(s.begin() + idx, s.end());
return s;
}
};
References
For additional details, please see the Discussion Board where you can find plenty of well-explained accepted solutions with a variety of languages including low-complexity algorithms and asymptotic runtime/memory analysis1, 2.

Function won't reverse strings properly

#include <iostream>
#include <cstring>
using namespace std;
void reverseString(char s[])
{
int length = strlen(s);
for (int i = 0; s[i] != '\0'; i++) {
char temp = s[i];
s[i] = s[length - i - 1];
s[length - i - 1] = temp;
cout << s[i]; //this ends up printing "eooe" instead of reversing the whole string
}
}
int main()
{
char a[] = "Shoe";
reverseString(a);
return 1;
}
I'm wondering where the algorithm messes up and what I can do to fix it, maybe I overlooked something because when I try to solve it on a piece of paper it appears to work correctly.
Your algo is right but need a little modification, you have to run algorithm for length/2 times. It prevents your string to again swap the contents i.e At i = 2 your s = eohs but it again swaps h with o. Try to insert the break point to understand it further. I modify your function little bit.
char* reverseString(char s[])
{
int length = strlen(s);
for (int i = 0; i<length/2; i++)
{
char temp = s[i];
s[i] = s[length - i - 1];
s[length - i - 1] = temp;
//cout << s[i]; //this ends up printing "eooe" instead of reversing the whole string
}
return s;
}
int main()
{
char a[] = "Shoe";
cout<<reverseString(a);
system("pause");
return 1;
}
Use the code below:
#include <stdio.h>
void strrev(char *p)
{
char *q = p;
while(q && *q) ++q;
for(--q; p < q; ++p, --q)
*p = *p ^ *q,
*q = *p ^ *q,
*p = *p ^ *q;
}
int main(int argc, char **argv)
{
do {
printf("%s ", argv[argc-1]);
strrev(argv[argc-1]);
printf("%s\n", argv[argc-1]);
} while(--argc);
return 0;
}

Write a snippet of C/C++ code that creates this list of base-12 numbers that count from 0000 to BBBB

Im not sure what to do i want it to print 0000 to ending in BBBB i was trying to use the printf statement anyways, if anyone can help me figure this out that would be great. Thanks
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
char digits[] = "0123456789AB";
for (int column1=0; column1<=12; column1++) {
for (int column2=0; column2<=12; column2++) {
for (int column3=0; column3<=12; column3++) {
for (int column4=0; column4<=12; column4++) {
std::cout<< digits[column2]<<endl;
}
}}}
return(0);
}
The 4 for loops are not the prettiest thing ever, but they should work and I'm not sure it's worth the complications to do it differently. So keep what you have, just print all digits:
std::cout<< digits[column1]<< digits[column2] << digits[column3] << digits[column4]<<endl;
It's better to parametrize the base and the column count to avoid many nested for's.
#include <iostream>
const int columnCount = 4, base = 12;
char digitToChar(int digit) {
if(digit >= 0 && digit <= 9) {
return '0' + digit;
} else {
return 'A' + digit - 10;
}
}
bool increment(int* number) {
int currentColumn = columnCount - 1;
++number[currentColumn];
while(number[currentColumn] == base) {
number[currentColumn] = 0;
--currentColumn;
if(currentColumn < 0) {
return false;
}
++number[currentColumn];
}
return true;
}
void outputNumber(int* number) {
for(int i = 0; i < columnCount; ++i) {
std::cout << digitToChar(number[i]);
}
std::cout << std::endl;
}
int main() {
int number[columnCount] = {0, 0, 0, 0};
bool overflow = false;
do {
outputNumber(number);
overflow = !increment(number);
} while(!overflow);
return 0;
}

C++ vector and string, count vowels

This program supposed to read a text and count the number of vowels and consonants. it should ignore any non alphabetic characters. the result should me something like this:
Enter your text: I have to TURN this..in before midnight!!
a, e, i, o, u, y
1, 3, 5, 2, 1, 0
There are 19 consonants.
but the result from my code is :
Enter your text: I have to TURN this..in before midnight!!
a, e, i, o, u, y
1, 3, 4, 2, 0, 0
There are 31 consonants.
I dont know what is happening!! Also this is an assignment and I have to use all these functions and I cannot add or remove them! I read couple of other ways to count and display the numbers but unfortunately the template was given...
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
using namespace std;
// FUNCTION PROTOTYPES GO HERE:
void init_vectors(vector<char> & vowels, vector<int> & frequencies);
string read_text(const string & prompt);
bool is_alphabetic(const char character);
void create_list(const string & str_text, vector<char> & vec_text);
bool is_member(const vector<char> & list, char character);
int find_index(const vector<char> & list, char character);
int compute_vowel_freqs(const vector<char> & text, const vector<char> & vowels, vector<int> & freqs);
void display_characters(const vector<char> & characters, const int colwidth);
void display_freqs(const vector<int> & freqs, const int colwidth);
int main()
{
vector<char> vowels;
vector<int> freqs;
string input;
vector<char> text;
int consonants(0);
const int COLUMNWIDTH = 2;
init_vectors(vowels, freqs);
input=read_text("Enter your text: ");
create_list(input, text);
compute_vowel_freqs(text, vowels, freqs);
display_characters(vowels, COLUMNWIDTH);
display_freqs(freqs, COLUMNWIDTH);
consonants = compute_vowel_freqs(text, vowels, freqs);
cout<<"There are "<< consonants<< " consonants."<<endl;
return 0;
}
void init_vectors(vector<char> & vowels, vector<int> & frequencies)
{
for (int i(0); i<6; i++) //i is loop variable
{
frequencies.push_back(0);
}
vowels.push_back('a');
vowels.push_back('e');
vowels.push_back('i');
vowels.push_back('o');
vowels.push_back('u');
vowels.push_back('y');
}
string read_text(const string & prompt)
{
string phrase;
cout<<prompt;
getline(cin,phrase);
return phrase;
}
bool is_alphabetic(const char character)
{
bool alphabet;
if ((character > 'a' && character < 'z')||(character > 'A' && character < 'Z'))
{
alphabet = true;
}
return alphabet;
}
void create_list(const string & str_text, vector<char> & vec_text)
{
for( int i = 0 ; i < str_text.length() ; i++)
{
if(is_alphabetic(str_text[i]))
vec_text.push_back(str_text[i]);
}
}
bool is_member(const vector<char> & list, char character)
{
bool vowel;
for (int i(0); i<list.size(); i++)
{
if (character == list[i])
{
vowel=true;
}
}
return vowel;
}
int find_index(const vector<char> & list, char character)
{
int index = -1;
for(int i=0; i<list.size(); i++)
{
if(character == list[i])
{
index = i;
break;
}
}
return index;
}
int compute_vowel_freqs(const vector<char> & text, const vector<char> & vowels, vector<int> & freqs)
{
int num_cons(0);
for(int i = 0 ; i < text.size() ; i++)
{
int index;
if(is_member(vowels, text[i]))
{
index = find_index(vowels , tolower(text[i]));
freqs[index]++;
}
else
num_cons++;
}
return num_cons;
}
void display_characters(const vector<char> & characters, const int colwidth)
{
for(int i=0; i<characters.size(); i++)
{
cout<<setw(colwidth)<<characters[i];
if((i+1)<characters.size())
{
cout<<",";
}
}
cout<<endl;
return;
}
void display_freqs(const vector<int> & freqs, const int colwidth)
{
for(int i=0; i<freqs.size(); i++)
{
cout<<setw(colwidth)<<freqs[i];
if((i+1)<freqs.size())
cout<<",";
}
cout<<endl;
return;
}
If you write hundreds of lines of code before you test any of it, you're bound to fail. Start small and simple, add complexity a little at a time, test at every step, and never add to code that doesn't work.
You should have tested these functions one by one as you wrote them. Here's the first problem:
bool is_alphabetic(const char character)
{
bool alphabet;
if ((character > 'a' && character < 'z')||(character > 'A' && character < 'Z'))
{
alphabet = true;
}
return false;
}
This always returns false, so nothing is recognized as text.
EDIT:
Second problem: is_member has exactly the same bug, with the same solution.
EDIT:
Third problem: I failed to notice that in this line in is_alphabetic:
if ((character > 'a' && character < 'z')||(character > 'A' && character < 'Z'))
You're using '>' and '<' when you should use ">=" and "<=". According to this function, 'a' and 'z' are not letters.
Look, you're still trying to test and fix this program as a whole. You must test it piecemeal. Pick a place in main and print out every variable that should have been assigned a value by then. This function may be useful:
void printVector(const vector<char> &V)
{
for(vector<char>::const_iterator citr=V.begin(); citr!=V.end(); ++citr)
cout << *citr;
cout << endl;
}
Then inspect the results. If a variable doesn't contain what it should, then something above that point is misbehaving. Trace the problem back to a function where good things go in but something bad comes out. Fix that, then look at the output again. I can't emphasize this enough: don't try to fix everything at once.
Your is_member is always false, so no char is vowel. And it results in 0 count.
bool is_member(const vector<char> & list, char character)
{
bool vowel = false; # this fix is not obligatory, I just made code look clearer
for (int i(0); i<list.size(); i++)
{
if (character == list[i])
{
vowel=true;
}
}
return vowel; # this should be fixed
}
By the way, the same issue is in the function 'is_alphabetic'. It is always false.

Memory allocation and deallocation

Here is the entire program, please help me, I've tried everything to find out what exactly is going with the memory. The problem is everything runs perfectly, but there are some extra characters printed with output.
Here is the .h file:
class MyString
{
public:
MyString();
MyString(const char *message);
MyString(const MyString &source);
~MyString();
const void Print() const;
const int Length() const;
MyString& operator()(const int index, const char b);
char& operator()(const int i);
MyString& operator=(const MyString& rhs);
bool operator==(const MyString& other) const;
bool operator!=(const MyString& other) const;
const MyString operator+(const MyString& rhs) const;
MyString& operator+=(const MyString& rhs);
friend ostream& operator<<(ostream& output, const MyString& rhs);
const int Find(const MyString& other);
MyString Substring(int start, int length);
private:
char *String;
int Size;
};
istream& operator>>(istream& input, MyString& rhs);
The .cpp file:
MyString::MyString()
{
char temp[] = "Hello World";
int counter(0);
while(temp[counter] != '\0')
{
counter++;
}
Size = counter;
String = new char [Size];
for(int i=0; i < Size; i++)
String[i] = temp[i];
}
//alternate constructor that allows for setting of the inital value of the string
MyString::MyString(const char *message)
{
int counter(0);
while(message[counter] != '\0')
{
counter++;
}
Size = counter;
String = new char [Size];
for(int i=0; i < Size; i++)
String[i] = message[i];
}
//copy constructor
MyString::MyString(const MyString &source)
{
int counter(0);
while(source.String[counter] != '\0')
{
counter++;
}
Size = counter+1;
String = new char[Size];
for(int i = 0; i <= Size; i++)
String[i] = source.String[i];
}
//Deconstructor
MyString::~MyString()
{
delete [] String;
}
//Length() method that reports the length of the string
const int MyString::Length() const
{
int counter(0);
while(String[counter] != '\0')
{
counter ++;
}
return (counter);
}
/*Parenthesis operator should be overloaded to replace the Set and Get functions of your previous assignment. Note that both instances should issue exit(1) upon violation of the string array bounaries.
*/
MyString& MyString::operator()(const int index, const char b)
{
if(String[index] == '\0')
{
exit(1);
}
else
{
String[index] = b;
}
}
char& MyString::operator()(const int i)
{
if(String[i] == '\0')
{
exit(1);
}
else
{
return String[i];
}
}
/*Assignment operator (=) which will copy the source string into the destination string. Note that size of the destination needs to be adjusted to be the same as the source.
*/
MyString& MyString::operator=(const MyString& rhs)
{
if(this != &rhs)
{
delete [] String;
String = new char[rhs.Size];
Size = rhs.Size;
for(int i = 0; i < rhs.Size+1 ; i++)
{
String[i] = rhs.String[i];
}
}
return *this;
}
/*Logical comparison operator (==) that returns true iff the two strings are identical in size and contents.
*/
bool MyString::operator==(const MyString& other)const
{
if(other.Size == this->Size) {
for(int i = 0; i < this->Size+1; i++)
{
if(&other == this)
return true;
}
}
else
return false;
}
//Negated logical comparison operator (!=) that returns boolean negation of 2
bool MyString::operator!=(const MyString& other) const
{
return !(*this == other);
}
//Addition operator (+) that concatenates two strings
const MyString MyString::operator+(const MyString& rhs) const
{
char* tmp = new char[Size + rhs.Size +1];
for(int i = 0; i < Size; i++)
{
tmp[i] = String[i];
}
for(int i = 0; i < rhs.Size+1; i++) {
tmp[i+Size] = rhs.String[i];
}
MyString result;
delete [] result.String;
result.String = tmp;
result.Size = Size+rhs.Size;
return result;
}
/*Addition/Assigment operator (+=) used in the following fashion: String1 += String2 to operate as String1 = String1 + String2
*/
MyString& MyString::operator+=(const MyString& rhs)
{
char* tmp = new char[Size + rhs.Size + 1];
for(int i = 0; i < Size; i++) {
tmp[i] = String[i];
}
for(int i = 0; i < rhs.Size+1; i++)
{
tmp[i+Size] = rhs.String[i];
}
delete [] String;
String = tmp;
Size += rhs.Size;
return *this;
}
istream& operator>>(istream& input, MyString& rhs)
{
char* t;
int size(256);
t = new char[size];
input.getline(t,size);
rhs = MyString(t);
delete [] t;
return input;
}
ostream& operator<<(ostream& output, const MyString& rhs)
{
if(rhs.String != '\0')
{
output << rhs.String;
}
else
{
output<<"No String to output\n";
}
return output;
}
/*MyString::Find that finds a string in a larger string and returns the starting location of the substring. Note that your string location starts from 0 and ends at length -1. If the string is not found, a value of -1 will be returned
*/
const int MyString::Find(const MyString& other)
{
int nfound = -1;
if(other.Size > Size)
{
return nfound;
}
int i = 0, j = 0;
for(i = 0; i < Size; i++) {
for(j = 0; j < other.Size; j++) {
if( ((i+j) >= Size) || (String[i+j] != other.String[j]) )
{
break;
}
}
if(j == other.Size)
{
return i;
}
}
return nfound;
}
/*MyString::Substring(start, length). This method returns a substring of the original string that contains the same characters as the original string starting at location start and is as long as length.
*/
MyString MyString::Substring(int start, int length)
{
char* leo = new char[length+1];
for(int i = start; i < start + length+1; ++i)
{
leo[i-start] = String[i];
}
MyString sub;
delete [] sub.String; sub.String = leo; sub.Size = Size;
return sub;
}
//Print() method that prints the string
const void MyString::Print() const
{
for(int i=0; i < Size; i++)
{
cout<<String[i];
}
cout<<endl;
}
The main.cpp file:
int main (int argc, char **argv)
{
MyString String1;
const MyString ConstString("Target string"); //Test of alternate constructor
MyString SearchString; //Test of default constructor that should set "Hello World".
MyString TargetString (String1); //Test of copy constructor
cout << "Please enter two strings. ";
cout << "Each string needs to be shorter than 256 characters or terminated by /\n." << endl;
cout << "The first string will be searched to see whether it contains exactly the second string. " << endl;
cin >> SearchString >> TargetString; // Test of cascaded string-extraction operator
if(SearchString.Find(TargetString) == -1) {
cout << TargetString << " is not in " << SearchString << endl;
}
else {
cout << TargetString << " is in " << SearchString << endl;
cout << "Details of the hit: " << endl;
cout << "Starting position of the hit: " << SearchString.Find(TargetString) << endl;
cout << "The matching substring is: " << SearchString.Substring(SearchString.Find(TargetString), TargetString.Length()-1)<<"\n";
}
return 0;
}
Running the program you get this:
Please enter two strings. Each string needs to be shorter than 256 characters or terminated by /
.
The first string will be searched to see whether it contains exactly the second string.
firstly
real
realt World is not in firstly
Please Help!!
try adding a '\0' at the end of your strings in your MyString::MyString(const char *message) constructor
#Sam's answer is correct. I'm going to add on to it to help you learn what's happening.
C and C++ strings are really character arrays that follow a convention that the string is terminated with \0, sometimes called NUL (not null), which is a character where all bits are 0.
Your code gets the first part right in that it creates an array of characters. However, you do not apply the convention that the string must be NUL terminated.
You then pass a string that does not follow the NUL termination convention to cout, which does follow that convention. In other words, it runs through the string, printing each character to stdout, until it happens across the character \0 in memory. It's actually fairly lucky that it terminates. If there were not a \0 in the character array it is outputing, it would just keep on going until reaching a memory address that does not belong to your program and failing with a segmentation fault.

Resources