I have an issue with string::iterator. VS says string iterator not decrementable. My first project works fine with the same function Is_Palindrom
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <valarray>
#include <functional>
#include <iterator>
#include <algorithm>
#include <iterator>
#include <cctype>
using namespace std;
string Is_Palindrom(string str)
{
string::iterator iter = str.begin();
transform(str.begin(), str.end(), str.begin(), tolower);
for (iter; iter != str.end(); iter++)
{
if (ispunct(*iter) || *iter == *" ")
{
str.erase(iter);
iter--;
}
}
return str;
}
void main()
{
ostream_iterator<string, char>out(cout, "\n");
string tmp;
vector<string>str;
while (getline(cin, tmp) && tmp != "quit")
str.push_back(tmp);
transform(str.begin(), str.end(), out, Is_Palindrom);
}
But if I load some words from a .txt and apply Is_Palindrome function it crashes, but if I change string::iterator to a simple loop with a [ ] access it works correct.
Here the problem code.
#include <cstdlib>
#include <ctime>
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <valarray>
#include <functional>
#include <iterator>
#include <algorithm>
#include <iterator>
#include <cctype>
using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::tolower;
using std::endl;
using std::ifstream;
string Is_Palindrom(string str);
int main()
{
vector <string> wordlist;
std::srand(std::time(0));
ifstream fin;
fin.open("text.txt");
if (fin.is_open() == false)
{
std::cerr << "Can't open file. Bye.\n"; // не удается открыть файл
exit(EXIT_FAILURE);
}
string item;
int count = 0;
getline(fin, item, ' ');
wordlist.push_back(item);
transform(wordlist.begin(), wordlist.end(), wordlist.begin(), Is_Palindrom);
while (fin) // до тех пор, пока нет ошибок ввода
{
cout << count << " : " << wordlist[count] << endl;
++count;
getline(fin, item, ' ');
wordlist.push_back(item);
transform(wordlist.begin(), wordlist.end(), wordlist.begin(), Is_Palindrom);
}
cout << "Done\n";
fin.close();
char play;
cout << "Will you play a word game? <y/n> "; // запуск игры в слова
cin >> play;
play = tolower(play);
while (play == 'y')
{
string target = wordlist[std::rand() % wordlist.size()];
int length = target.length();
string attempt(length, '-');
string badchars;
int guesses = 6;
cout << "Guess my secret word. It has " << length
<< " letters, and you guess\n"
<< "one letter at a time. You get " << guesses
<< " wrong guesses.\n";
cout << "Your word: " << "attempt" << endl; // вывод слова
while (guesses > 0 && attempt != target)
{
char letter;
cout << "Guess a letter: ";
cin >> letter;
if (badchars.find(letter) != string::npos || attempt.find(letter) != string::npos)
{
cout << "You already guessed that. Try again.\n";
continue;
}
int loc = target.find(letter);
if (loc == string::npos)
{
cout << "Oh, bad guess !\n";
--guesses;
badchars += letter; // добавить к строке
}
else
{
cout << "Good guess!\n";
attempt[loc] = letter;
// Проверить, не появляется ли буква еще раз
loc = target.find(letter, loc + 1);
while (loc != string::npos)
{
attempt[loc] = letter;
loc = target.find(letter, loc + 1);
}
}
cout << "Your word: " << attempt << endl;
if (attempt != target)
{
if (badchars.length() > 0)
cout << "Bad choices: " << badchars << endl;
cout << guesses << " bad guesses left\n";
}
}
if (guesses > 0)
cout << "That's right!\n";
else
cout << "Sorry, the word is " << target << " . \n";
cout << "Will you play another? <y/n> ";
cin >> play;
play = tolower(play);
}
cout << "Bye\n";
return 0;
}
string Is_Palindrom(string str)
{
string::iterator iter = str.begin();
//for (int i = 0; i < str.length(); i++)
for (iter; iter != str.end(); iter++)
{
//if (ispunct(str[i]) || str[i] == *" ")
if (ispunct(*iter) || *iter == *" ")
{
//str.erase(i, 1);
//i--;
str.erase(iter, iter+1);
if (iter == str.end())
break;
iter--;
}
}
return str;
}
The problem in your code is
if (ispunct(*iter) || *iter == *" ")
{
str.erase(iter);
iter--;
}
First, if you want to check a character you should use ' not ". So your
statement should be
if (ispunct(*iter) || *iter == ' ')
//or even better
if (ispunct(*iter) || isspace(*iter))
Secondly, you are using erase(). When you call erase it invalidates all references and iterators to the current element to the end. Since you are using the same iterator that you used to delete the element this is undefined behavior. Just because it works in the first example doesn't mean it will work in another piece of code. Luckily erase() returns an iterator to the element after the erased element. We can capture that iterator and use that for the next iteration. In order to do this, you need to change your for loop into a while loop like:
while(iter != str.end())
{
if (ispunct(*iter) || isspace(*iter))
iter = str.erase(iter); // erase and don't increment as we are already on the next character
else
iter++; // increment since it was a valid character
}
Related
im going to write a small program where the user types in a email adress and the code have to check if the email includes a #: ive just started programing and this is what ive come up with so far:
#include <iostream>
#include <string>
using namespace std;
int main() {
cout << "Skriv in en Epostadress: \n";
string adress;
cin >> adress;
if (adress == "#"){
cout << "Giltig!";
}
else {
cout << "Ogiltig!";
}
return 0;
}
Use member function find of the class std::string.
if ( adress.find( '#' ) != std::string::npos ){
cout << "Giltig!";
}
else {
cout << "Ogiltig!";
}
Here is a demonstrative program.
#include <iostream>
#include <string>
int main()
{
std::string address( "Harald.Scherr#gmail.com" );
std::string::size_type pos;
if ( ( pos = address.find( '#' ) ) != std::string::npos )
{
std::cout << "The character '#' is found at position " << pos << '\n';
}
else
{
std::cout << "The character '#' is not found\n";
}
return 0;
}
Its output is
The character '#' is found at position 13
maybe your problem is that you are comparing the whole string with "#" which was never the case for you,
however if you are tring to find the "#" in the input string then you will need to look for it as a char using for loop, you are very lucky however that you can go over the string as an array of characters in c++
try this maybe:
for(int i=0; i<adress.size(); i++){
if (adress[i] == '#'){
cout << "Giltig!" << endl;
return 0;
}
}
cout << "Ogiltig!" << endl;
return 0;
I have a trouble with a search through a string, if I enter a word with only letters, it's work as needs, I though, the code works, but when I add a number in work, the code work also, the question that, is possible to accept only if my var contains only letters, and if it will find a number or symbol, to go at begining of code?
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
label:
string var1 = "";
cout << "Enter a word: ";
cin >> var1;
for (int i = 0; i < var1.size (); i++)
{
int uppercaseCHar = toupper (var1[i]);
if (uppercaseCHar < 'A' || uppercaseCHar > 'Z')
{
goto endloop;
cout << endl;
} else
goto label;
cout << endl;
}
endloop:
cout << "Yout word contains only letters";
}
Output:
Enter a word: work
Enter a word: wro1
Enter a word: 123
Yout word contains only letters
Here is a solution that uses std::all_of:
#include <iostream>
#include <string>
#include <cctype>
#include <algorithm>
int main()
{
bool isAllLetters = false;
do
{
std::string var1;
std::cout << "Enter a word: ";
std::cin >> var1;
// check if all characters are letters
isAllLetters = std::all_of(var1.begin(), var1.end(), [](char ch)
{ return std::isalpha(static_cast<unsigned char>(ch));});
if ( isAllLetters )
std::cout << "Your word contains only letters\n";
else
std::cout << "Your word contains stuff other than letters\n"
} while ( !isAllLetters );
}
Simple and efficient (C++17):
#include <algorithm>
#include <cctype>
#include <string_view>
bool all_of_alpha(std::string_view s)
{
return std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalpha(c); });
}
Avoid using goto as it will complicate debugging code in larger program , here's another way :
int main()
{
while (true) {
bool flag = false; // to check for numeric entry
string var1; // not req to initialize
cout << "Enter a word (press exit to end): ";
cin >> var1;
for (int i = 0; i < var1.size(); i++)
{
int uppercaseCHar = toupper(var1[i]);
if (!std::isalpha(uppercaseCHar))
{
flag = true;
break;
}
}
if (var1.compare("exit") == 0) break;
if (flag) {
cout << "Your word contains number";
cout << endl;
}
else
{
cout << "Your word contains only alphabets";
cout << endl;
}
}
}
You can also use regular expressions which will simplify the code further.
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main () {
regex reg_obj("^[A-Z]+$");
string var;
start_label:
cout << "Enter a word: ";
getline(cin, var);
if(regex_match(var, reg_obj))
goto endlabel;
else goto start_label;
endlabel:
cout << "your word contains only letters\n";
return 0;
};
Allow me to offer a more modern idiomatic version and assuming you only care about detecting alphabetic characters in the ASCII character set.
#include <iostream>
#include <algorithm>
#include <string>
int main()
{
std::string a = "abcdefgh";
std::string b = "abcd3fgh";
std::string c = "abcdefg0";
auto is_alpha = [](unsigned char c){ return std::isalpha(c); };
bool aContainsAlphas = std::all_of(a.begin(), a.end(), is_alpha);
bool bContainsAlphas = std::all_of(b.begin(), b.end(), is_alpha);
bool cContainsAlphas = std::all_of(c.begin(), c.end(), is_alpha);
std::cout << std::boolalpha;
std::cout << "A: " << aContainsAlphas << '\n'; // true
std::cout << "B: " << bContainsAlphas << '\n'; // false
std::cout << "C: " << cContainsAlphas << '\n'; // false
}
This defines a lambda which is passed as an argument to std::all_of, which uses it to test each character:
auto is_alpha = [](unsigned char c){ return std::isalpha(c); };
This invokes is_alpha on each element between a.begin() and a.end(). If the end is reached without any mismatch for is_alpha, then true is returned.
bool aContainsAlphas = std::all_of(a.begin(), a.end(), is_alpha) != a.end();
I am trying to write a program to find specific word in several sentences, but something went wrong when I tried to input a word, I've tried cin.ignore(),cin.sync() and cin.clear(), all not working.
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> svec;
cout << "please input text:(at most 10 lines): " << endl;
while(svec.size() < 10) {
string sentence;
getline(cin, sentence);
transform(sentence.begin(), sentence.end(), sentence.begin(), ::tolower);
svec.push_back(sentence);
if(cin.eof())
break;
}
// I tried to clean up cin here by
// cin.ignore() , cin.sync() and cin.clear()
// none of them work
string wordToFind;
cout << "please input the pattern: ";
cin >> wordToFind; // This line isn't working
// If I print out wordToFind, it contains nothing
transform(wordToFind.begin(), wordToFind.end(), wordToFind.begin(), ::tolower);
bool isFind = false;
int whichLine = 1;
for(vector<string>::iterator iter = svec.begin(); iter != svec.end(); iter++, whichLine++) {
size_t pos = 0;
while((pos = iter->find(wordToFind, pos)) != string::npos) {
cout << "Found at" << endl;
cout << "Line " << whichLine << " column " << pos++ << endl;
isFind = true;
}
}
if(isFind == false)
cout << wordToFind << " not found";
return 0;
}
I have no idea what is going on for cin, is that a problem of the cin buffer or other related issue?
I have created a function that reads from a text file, adds content to a vector, shows the contacts. Then it prompts the user to choose which contact to remove. The program removes the contact but it removes other contacts as well (not all of them).
Here is the code:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdio>
#include <iomanip>
using namespace std;
vector<string> contakt;
void deleteContact()
{
ifstream input;
input.open("contacts.txt");
string entry;
int contactID=0;
int index = contactID;
while (getline(input, entry))
{
contakt.push_back(entry);
}
input.close();
cout << "\n\n\nCurrent contacts in list: "<< endl;
if (contakt.size() == 0) cout << "Empty" <<endl;
for (int i = 0; i < contakt.size(); i++)
{
cout << i << ") " << contakt[i] << endl;
}
cout<< " Enter the Id of the contact you would like to remove"<<endl;
cin>> contactID;
if (index != -1)
{
ofstream output;
output.open("temp.txt");
for (vector<string>::iterator it = contakt.begin(); it!= contakt.end(); it++)
{
contakt.erase(contakt.begin() + index);
output<< *it <<'\n';
}
remove("contacts.txt");
rename("temp.txt", "contacts.txt");
output.close();
cout << "Contact deleted succesfull." << endl;
}
else cout << "\nNote: Id was not found in file." <<endl;
return;
}
code here
I remade the function from the beggining and now i am facing another problem.
At the end of the file a blank space is created whenever i remove a contact.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
void deleteContact()
{
vector<string> file;
string temp;
ifstream input("contacts.txt");
while( !input.eof() )
{
getline(input, temp);
file.push_back(temp);
}
input.close();
string item;
cout << "Enter an name to delete from the contacts: ";
cin>>item;
int t = 0;
for(int i = 0; i < (int)file.size(); ++i)
{
if(file[i].substr(0, item.length()) == item)
{
file.erase(file.begin() + i);
cout << "Order erased!"<< endl;
i = 0; // Reset search
t++;
}
}
if (t == 0) cout<< "There is no contact with that name!!"<< endl;
ofstream output("contacts.txt", ios::out | ios::trunc);
for(vector<string>::const_iterator i = file.begin(); i != file.end(); ++i)
{
output << *i << '\n';
}
output.close();
return;
}
Your code modifies the vector while it iterates over it.
This invalidates the iterator.
Retrieve the updated iterator returned from the erase() function.
More details here: iterate vector, remove certain items as I go
Or, as you seem to delete just one contact at a time, just break your for loop after the first call to erase.
I am still a beginner and I am learning from a book. There was a drill that asked me filter input based on a vector of filtered words and if it was one of them it outputs "bad word"
Here is the drill exactly as in the book.
Try This
Write a program that “bleeps” out words that you don’t like; that is, you read in words using cin and print them again on cout. If a word is among a few you have defined, you write out BLEEP instead of that word. Start with one “disliked word” such as string disliked = “Broccoli”
When that works, add a few more.;
Here is the code I wrote:
#include <D:\std_lib_facilities.h>
int main()
{
// RL: omitting actual "bad" words to protect the innocent...
vector <string> bwords { "word1", "word2", "word3" };
vector <string> words;
string input = "";
while(cin >> input)
{
words.push_back(input);
}
double counter1 = 0;
double counter2 = 0;
while(counter1 < bwords.size() && counter2 < words.size())
{
if(bwords[counter1] == words[counter2])
{
cout << " bad word ";
}
else if (counter1 == bwords.size() - 1 && counter2 != words.size() )
{
cout << " "<< words[counter2] <<" ";
counter1 = 0;
}
else
{
++counter1;
counter2 += 1 / bwords.size();
}
}
}
whenever it starts it just tests the first word and repeats its self as if just tests the first if condition.
You over-complicated your loop. Try something more like this instead:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// RL: omitting actual "bad" words to protect the innocent...
const vector <string> bwords { "word1", "word2", "word3" };
string bleepWordIfBad(const string &word)
{
if (std::find(bwords.begin(), bwords.end(), word) != bwords.end())
return "BLEEP";
else
return word;
}
int main()
{
vector <string> words;
string input;
while (cin >> input)
words.push_back(input);
for (int counter = 0; counter < words.size(); ++counter)
cout << " " << bleepWordIfBad(words[counter]) << " ";
/*
Alternatively:
for (vector<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
cout << " " << bleepWordIfBad(*iter) << " ";
*/
/*
Alternatively:
for (const string &word : words)
cout << " " << bleepWordIfBad(word) << " ";
*/
return 0;
}
Or, get rid of the manual loop altogether:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// RL: omitting actual "bad" words to protect the innocent...
const vector <string> bwords { "word1", "word2", "word3" };
string bleepWordIfBad(const string &word)
{
if (std::find(bwords.begin(), bwords.end(), word) != bwords.end())
return "BLEEP";
else
return word;
}
void outputWord(const string &word)
{
cout << " " << bleepWordIfBad(word) << " ";
}
int main()
{
vector <string> words;
string input;
while (cin >> input)
words.push_back(input);
for_each(words.begin(), words.end(), outputWord);
/*
Alternatively:
for_each(words.begin(), words.end(),
[](const string &word) { cout << " " << bleepWordIfBad(word) << " "; }
);
*/
return 0;
}
Or, get rid of the input vector altogether and just filter the user's input as it is being entered:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// RL: omitting actual "bad" words to protect the innocent...
const vector <string> bwords { "word1", "word2", "word3" };
string bleepWordIfBad(const string &word)
{
if (std::find(bwords.begin(), bwords.end(), word) != bwords.end())
return "BLEEP";
else
return word;
}
int main()
{
string word;
while (cin >> word)
cout << " " << bleepWordIfBad(word) << " ";
return 0;
}