How do i remove every odd time appeared character in string? - c++

I have a string that contains only A, B, C, D. I need to remove all odd-appeared characters in this string. For example if string is "ABBBCA" it will turn into "BA" (first "A" removed because it was first time "A" appeared, then first and third "B" removed, and "C" also, because it was first time it appeared). I'm beginner in coding, so i'm sorry if this question is too simple or something.
I have tried something like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string firstchars = "ABBBCA";
for (int o = 0; o < firstchars.length(); o ++) {
firstchars.erase(o,1);
}
But it just erases every odd element in string, not every odd "A", "B", "C" and "D".
And i have "BBA" as output.

Something along these lines, perhaps:
std::string s = "ABBBCA";
std::bitset<4> seen;
s.erase(
std::remove_if(s.begin(), s.end(), [&](char c) {
return seen[c - 'A'].flip();
}),
s.end()
);
Demo

Related

Understanding String::Find In C++

I've been given a programming task that involves taking away certain letters in a string. I was trying out different ways to do this when I found the public member function string find. To put it short I was testing out the function via this program :
#include <iostream>
#include <string>
using namespace std;
int main()
{
string Word = "Applejuice";
cout<<Word.find("e")<<endl;
return 0;
}
So when I put in a letter such as "e" I get the number 4 which confuses me because I thought the function will count all the letters in that specific word such as apple juice. Also, when I use a letter that is not used in that word I get numbers like 18446744073709551615 for example when I put in X for e in the code above.
Could someone explain why this is happening, please?
string.find() will return the position of the first character of the first match.
If no matches were found, the function returns string::npos.
Therefore the number (18446744073709551615) you are getting is the string::npos
If you want to search for an only a single character in the string you can use the following code
#include <iostream>
#include <string>
using namespace std;
// Function that return count of the given
// character in the string
int count(string s, char c)
{
// Count variable
int res = 0;
for (int i=0;i<s.length();i++)
// checking character in string
if (s[i] == c)
res++;
return res;
}
// Driver code
int main()
{
string str= "Applejuice";
char c = 'e';
cout << count(str, c) << endl;
return 0;
}
If you want to avoid some random large values as output i.e. string::npos you can just add check for it like following:
if(Word.find("e") != string::npos)
{
...
}
Method find from class string return the position of the first character of the first match. Return type of find is size_t and since size_t is unsigned integral so if no match were found return string::nopos so you should compare the outputof find with string::nopos.
if(Word.find("e") != string::nopos)
{
...
}

How to delete part of a string c++ [duplicate]

I got a string and I want to remove all the punctuations from it. How do I do that? I did some research and found that people use the ispunct() function (I tried that), but I cant seem to get it to work in my code. Anyone got any ideas?
#include <string>
int main() {
string text = "this. is my string. it's here."
if (ispunct(text))
text.erase();
return 0;
}
Using algorithm remove_copy_if :-
string text,result;
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(result), //Store output
std::ptr_fun<int, int>(&std::ispunct)
);
POW already has a good answer if you need the result as a new string. This answer is how to handle it if you want an in-place update.
The first part of the recipe is std::remove_if, which can remove the punctuation efficiently, packing all the non-punctuation as it goes.
std::remove_if (text.begin (), text.end (), ispunct)
Unfortunately, std::remove_if doesn't shrink the string to the new size. It can't because it has no access to the container itself. Therefore, there's junk characters left in the string after the packed result.
To handle this, std::remove_if returns an iterator that indicates the part of the string that's still needed. This can be used with strings erase method, leading to the following idiom...
text.erase (std::remove_if (text.begin (), text.end (), ispunct), text.end ());
I call this an idiom because it's a common technique that works in many situations. Other types than string provide suitable erase methods, and std::remove (and probably some other algorithm library functions I've forgotten for the moment) take this approach of closing the gaps for items they remove, but leaving the container-resizing to the caller.
#include <string>
#include <iostream>
#include <cctype>
int main() {
std::string text = "this. is my string. it's here.";
for (int i = 0, len = text.size(); i < len; i++)
{
if (ispunct(text[i]))
{
text.erase(i--, 1);
len = text.size();
}
}
std::cout << text;
return 0;
}
Output
this is my string its here
When you delete a character, the size of the string changes. It has to be updated whenever deletion occurs. And, you deleted the current character, so the next character becomes the current character. If you don't decrement the loop counter, the character next to the punctuation character will not be checked.
ispunct takes a char value not a string.
you can do like
for (auto c : string)
if (ispunct(c)) text.erase(text.find_first_of(c));
This will work but it is a slow algorithm.
Pretty good answer by Steve314.
I would like to add a small change :
text.erase (std::remove_if (text.begin (), text.end (), ::ispunct), text.end ());
Adding the :: before the function ispunct takes care of overloading .
The problem here is that ispunct() takes one argument being a character, while you are trying to send a string. You should loop over the elements of the string and erase each character if it is a punctuation like here:
for(size_t i = 0; i<text.length(); ++i)
if(ispunct(text[i]))
text.erase(i--, 1);
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string str = "this. is my string. it's here.";
transform(str.begin(), str.end(), str.begin(), [](char ch)
{
if( ispunct(ch) )
return '\0';
return ch;
});
}
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;//string is defined here.
cout << "Please enter a string with punctuation's: " << endl;//Asking for users input
getline(cin, s);//reads in a single string one line at a time
/* ERROR Check: The loop didn't run at first because a semi-colon was placed at the end
of the statement. Remember not to add it for loops. */
for(auto &c : s) //loop checks every character
{
if (ispunct(c)) //to see if its a punctuation
{
c=' '; //if so it replaces it with a blank space.(delete)
}
}
cout << s << endl;
system("pause");
return 0;
}
Another way you could do this would be as follows:
#include <ctype.h> //needed for ispunct()
string onlyLetters(string str){
string retStr = "";
for(int i = 0; i < str.length(); i++){
if(!ispunct(str[i])){
retStr += str[i];
}
}
return retStr;
This ends up creating a new string instead of actually erasing the characters from the old string, but it is a little easier to wrap your head around than using some of the more complex built in functions.
I tried to apply #Steve314's answer but couldn't get it to work until I came across this note here on cppreference.com:
Notes
Like all other functions from <cctype>, the behavior of std::ispunct
is undefined if the argument's value is neither representable as
unsigned char nor equal to EOF. To use these functions safely with
plain chars (or signed chars), the argument should first be converted
to unsigned char.
By studying the example it provides, I am able to make it work like this:
#include <string>
#include <iostream>
#include <cctype>
#include <algorithm>
int main()
{
std::string text = "this. is my string. it's here.";
std::string result;
text.erase(std::remove_if(text.begin(),
text.end(),
[](unsigned char c) { return std::ispunct(c); }),
text.end());
std::cout << text << std::endl;
}
Try to use this one, it will remove all the punctuation on the string in the text file oky.
str.erase(remove_if(str.begin(), str.end(), ::ispunct), str.end());
please reply if helpful
i got it.
size_t found = text.find('.');
text.erase(found, 1);

Count unique words in a string in C++

I want to count how many unique words are in string 's' where punctuations and newline character (\n) separates each word. So far I've used the logical or operator to check how many wordSeparators are in the string, and added 1 to the result to get the number of words in string s.
My current code returns 12 as the number of word. Since 'ab', 'AB', 'aB', 'Ab' (and same for 'zzzz') are all same and not unique, how can I ignore the variants of a word? I followed the link: http://www.cplusplus.com/reference/algorithm/unique/, but the reference counts unique item in a vector. But, I am using string and not vector.
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool isWordSeparator(char & c) {
return c == ' ' || c == '-' || c == '\n' || c == '?' || c == '.' || c == ','
|| c == '?' || c == '!' || c == ':' || c == ';';
}
int countWords(string s) {
int wordCount = 0;
if (s.empty()) {
return 0;
}
for (int x = 0; x < s.length(); x++) {
if (isWordSeparator(s.at(x))) {
wordCount++;
return wordCount+1;
int main() {
string s = "ab\nAb!aB?AB:ab.AB;ab\nAB\nZZZZ zzzz Zzzz\nzzzz";
int number_of_words = countWords(s);
cout << "Number of Words: " << number_of_words << endl;
return 0;
}
What you need to make your code case-insensitive is tolower().
You can apply it to your original string using std::transform:
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
I should add however that your current code is much closer to C than to C++, perhaps you should check out what standard library has to offer.
I suggest istringstream + istream_iterator for tokenizing and either unique_copy or set for getting rid of the duplicates, like this: https://ideone.com/nb4BEH
You could create a set of strings, save the position of the last separator (starting with 0) and use substring to extract the word, then insert it into the set. When done just return the set's size.
You could make the whole operation easier by using string::split - it tokenizes the string for you. All you have to do is insert all of the elements in the returned array to the set and again return it's size.
Edit: as per comments, you need a custom comparator to ignore case for comparisons.
First of all I'd suggest rewriting isWordSeparator like this:
bool isWordSeparator(char c) {
return std::isspace(c) || std::ispunct(c);
}
since your current implementation doesn't handle all the punctuation and space, like \t or +.
Also, incrementing wordCount when isWordSeparator is true is incorrect for example if you have something like ?!.
So, a less error-prone approach would be to substitute all separators by space and then iterate words inserting them into an (unordered) set:
#include <iterator>
#include <unordered_set>
#include <algorithm>
#include <cctype>
#include <sstream>
int countWords(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), [](char c) {
if (isWordSeparator(c)) {
return ' ';
}
return std::tolower(c);
});
std::unordered_set<std::string> uniqWords;
std::stringstream ss(s);
std::copy(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string(), std::inserter(uniqWords));
return uniqWords.size();
}
While splitting the string into words, insert all words into a std::set. This will get rid of the duplicates. Then it's just a matter of calling set::size() to get the number of unique words.
I'm using the boost::split() function from the boost string algorithm library in my solution, because is almost standard nowadays.
Explanations in the comments in code...
#include <iostream>
#include <string>
#include <set>
#include <boost/algorithm/string.hpp>
using namespace std;
// Function suggested by user 'mshrbkv':
bool isWordSeparator(char c) {
return std::isspace(c) || std::ispunct(c);
}
// This is used to make the set case-insensitive.
// Alternatively you could call boost::to_lower() to make the
// string all lowercase before calling boost::split().
struct IgnoreCaseCompare {
bool operator()( const std::string& a, const std::string& b ) const {
return boost::ilexicographical_compare( a, b );
}
};
int main()
{
string s = "ab\nAb!aB?AB:ab.AB;ab\nAB\nZZZZ zzzz Zzzz\nzzzz";
// Define a set that will contain only unique strings, ignoring case.
set< string, IgnoreCaseCompare > words;
// Split the string by using your isWordSeparator function
// to define the delimiters. token_compress_on collapses multiple
// consecutive delimiters into only one.
boost::split( words, s, isWordSeparator, boost::token_compress_on );
// Now the set contains only the unique words.
cout << "Number of Words: " << words.size() << endl;
for( auto& w : words )
cout << w << endl;
return 0;
}
Demo: http://coliru.stacked-crooked.com/a/a3b51a6c6a3b4ee8
You can consider SQLite c++ wrapper

Removing character from string c++

I am trying to remove a specific character from a string but am having difficulties.
Ive tried using replace() and replacing the character with nothing, but the compiler complains about that.
string s = "Hello, this is a test";
replace (s.begin(), s.end(), 'l', '');
cout << s;
What i would like is for it to find and remove the character 'l' so it outputs "Heo, this is a test".
Unfortunately i don't think replace() is the correct thing to use and am a bit stumped. Have only been learning programming for a couple weeks, so I'm sorry if this is a dumb question. Thanks :)
This is pretty staight foward. If you want to replace Hello with Heo call the function with these parameters ReplaceWord(str, "Hello", "Heo").
Please note that this example is case sensitive so if you use a lowercase h, it will not replace at all, it wont find the word, it has to be a uppercase H.
#include <iostream>
#include <string>
using namespace std;
void ReplaceWord( std::string& source, const char* WordToFind, const char* WordToReplace );
//program entry point
int main (){
cout<<""<<endl;
string str = "Hello, this is a test";
cout<<"Before replace : "<<endl;
cout<<str<<endl;
cout<<""<<endl;
ReplaceWord(str, "Hello", "Heo");
cout<<"After replace : "<<endl;
cout<<str<<endl;
cout<<""<<endl;
return 0;
}
void ReplaceWord( std::string& source, const char* WordToFind, const char* WordToReplace ){
size_t LengthOfWordToReplace = strlen(WordToFind);
size_t replaceLen = strlen(WordToReplace);
size_t positionToSearchAt = 0;
//search for the next word
while ((positionToSearchAt = source.find(WordToFind, positionToSearchAt)) != std::string::npos)
{
//replace the found word with the new word
source.replace( positionToSearchAt, LengthOfWordToReplace, WordToReplace );
// move to next position
positionToSearchAt += replaceLen;
}
}
Hoping that you have added #include<algorithm>, the error message should complain about the empty character constant. You have to use '\0' for null character.
std::replace (s.begin(), s.end(), 'l', '\0');
Since you are new to programming, I would tell you that it is better(a good practice) to use the namespace name along with the function rather than having using namespace std in your code.
Considering the comment from #mindriot fro this answer, I prefer to give another solution:
s.erase( std::remove( s.begin(), s.end(), 'l' ), s.end() ) ;
You can also have a look at here for other related options.

Finding character in String in Vector

Judging from the title, I kinda did my program in a fairly complicated way. BUT! I might as well ask anyway xD
This is a simple program I did in response to question 3-3 of Accelerated C++, which is an awesome book in my opinion.
I created a vector:
vector<string> countEm;
That accepts all valid strings. Therefore, I have a vector that contains elements of strings.
Next, I created a function
int toLowerWords( vector<string> &vec )
{
for( int loop = 0; loop < vec.size(); loop++ )
transform( vec[loop].begin(), vec[loop].end(),
vec[loop].begin(), ::tolower );
that splits the input into all lowercase characters for easier counting. So far, so good.
I created a third and final function to actually count the words, and that's where I'm stuck.
int counter( vector<string> &vec )
{
for( int loop = 0; loop < vec.size(); loop++ )
for( int secLoop = 0; secLoop < vec[loop].size(); secLoop++ )
{
if( vec[loop][secLoop] == ' ' )
That just looks ridiculous. Using a two-dimensional array to call on the characters of the vector until I find a space. Ridiculous. I don't believe that this is an elegant or even viable solution. If it was a viable solution, I would then backtrack from the space and copy all characters I've found in a separate vector and count those.
My question then is. How can I dissect a vector of strings into separate words so that I can actually count them? I thought about using strchr, but it didn't give me any epiphanies.
Solution via Neil:
stringstream ss( input );
while( ss >> buffer )
countEm.push_back( buffer );
From that I could easily count the (recurring) words.
Then I did a solution via Wilhelm that I will post once I re-write it since I accidentally deleted that solution! Stupid of me, but I will post that once I have it written again ^^
I want to thank all of you for your input! The solutions have worked and I became a little better programmer. If I could vote up your stuff, then I would :P Once I can, I will! And thanks again!
If the words are always space separated, the easiest way to split them is to use a stringstream:
string words = .... // populat
istringstream is( words );
string word;
while( is >> word ) {
cout << "word is " << word << endl;
}
You'd want to write a function to do this, of course, and apply it to your strings. Or it may be better not to store the strings at allm but to split into words on initial input.
You can use std::istringstream to extract the words one by one and count them. But this solution consumes O(n) in space complexity.
string text("So many words!");
size_t count = 0;
for( size_t pos(text.find_first_not_of(" \t\n"));
pos != string::npos;
pos = text.find_first_not_of(" \t\n", text.find_first_of(" \t\n", ++pos)) )
++count;
Perhaps not as short as Neil's solution, but takes no space and extra-allocation other than what's already used.
Use a tokenizer such as the one listed here in section 7.3 to split the strings in your vector into single words (or rewrite it so that it just returns the number of tokens) and loop over your vector to count the total number of tokens you encounter.
Since C++11 there is a special and very powerful iterator, for iterating over patterns (for example words) in a string: The std::sregex_token_iterator
With that and iterator function std::distance, we can simply count all words (or other patterns in a string, by calculating the distance between the first and the last pattern.
The resulting program is always a one-liner:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <regex>
const std::regex re{R"(\w+)"};
const std::string test{"the quick brown fox jumps over the lazy dog"};
int main()
{
std::cout << std::distance(std::sregex_token_iterator(test.begin(), test.end(), re), {});
}
With this method, we can of course also split the string and show the resulting words:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <regex>
const std::regex re{R"(\w+)"};
const std::string test{"the quick brown fox jumps over the lazy dog"};
int main()
{
std::copy(std::sregex_token_iterator(test.begin(), test.end(), re), {}, std::ostream_iterator<std::string>(std::cout, "\n"));
}
By using the std::vectors range constructor, we can store also the words in a std::vector:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <regex>
#include <vector>
const std::regex re{R"(\w+)"};
const std::string test{"the quick brown fox jumps over the lazy dog"};
int main()
{
std::vector<std::string> words(std::sregex_token_iterator(test.begin(), test.end(), re), {});
std::cout << words.size();
}
You see. There are really many possibilities.
If you have a stream, then you can use the std::istream iterator for the same purpose-