Input string in C++ do while - c++

I'm trying to read a string as an input.
The string can only contain A C G and T letters and the length can't be more than 20000.
If the length is more than 20000 or it contains any other letter than A C G or T print out "error" and read again.
EXAMPLE INPUT: ACCGGTATTTACG
Here's my code and currently it prints error for every input.
int main()
{
string str;
string tmp;
bool hiba;
do{
cout<<"Str: ";cin>>str;
for(int x = 0;x < str.length();x++){
hiba = (cin.fail() || str[x] != 'A' || str[x] != 'C' ||str[x] != 'G' ||str[x] != 'T' || str.length() > 20000);
if(hiba){
cout<<"Error\n";
cin.clear();
getline(cin,tmp);
break;
}
}
}while(hiba);
}

Here is a direct transliteration of your requirements. Note the use of std::string::find_first_not_of to find "bad" characters. Also note that it returns an empty string should std::cin >> sequence fail. You need to handle that corner case.
std::string read_dna(int max_length) {
std::string sequence;
while (std::cin >> sequence) {
if (sequence.length() > max_length ||
sequence.find_first_not_of("ACGT") != std::string::npos) {
std::cerr << "error" << std::endl;
} else {
return sequence;
}
}
return std::string{};
}

Related

while Infinite loop in function

bool isDigital(char c) { return ('0' <= c && c <= '9'); }
void DigitalToken( char digitToken[50], char ch ) {
digitToken[0] = ch;
char input = '\0';
cin >> input;
int i = 0;
while ( ( input != ' ' ) && ( input != '\t' ) && ( input != '\n' ) ) { // got a infinite loop
i++;
digitToken[i] = input;
cin >> input;
} // while ( input != ' ' && input != '\t' && input != '\n' )
} // DigitalToken()
int main() {
char ch = '\0';
while ( cin >> ch ) {
if ( isDigital(ch) ) {
char* digitToken = new char[50]();
DigitalToken(digitToken, ch);
cout << digitToken;
delete[] digitToken;
} // else if
} // while
} // main()
I don't understand why I got a infinite loop in DitgitalToken function.
When I input 123, it should be output 123.
I watched it for a long time, but I still don’t know why and how to fix it.
Instead of cin >> input; use input = cin.get();.
You have to be careful while using cin with characters or strings. It treats spaces, tabs, newlines as end of the input and hence do not treat them as input themselves.
Your program blocks in the while loop on cin >> input; after it read "123". As #Arty suggested use cin.get() instead as whitespace is stripped by default. You can also use cin >> noskipws; prior to executing cin >> input;. See skipws.

Config file parser is only returning previous value

I have a small block of code, which is used to read the configuration file and then find for the specific value based on the key. My program now looks something like this:
string readConfigFile(string configKey) {
cout << "ReadConfigFile\n";
fstream drConfig("/usr/share/dr_config");
if(drConfig.is_open()) {
string line;
string value;
while (getline(drConfig, line))
{
line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end());
if(line[0] == '#' || line.empty()){
continue;
}
auto delimiterPos = line.find("=");
auto name = line.substr(0, delimiterPos);
value = line.substr(delimiterPos + 1);
// Use this to find a specific string
if (line.find(configKey) != std::string::npos) {
cout << value << endl;
}
}
return value;
} else {
return "Couldn't open the config file!\n";
}
}
In my main code I call it something like this:
string num1 = readConfigFile("120");
stringstream geek(num1);
int x = 0;
geek >> x;
cout << "The value of x is " << x << "\n";
string num2 = readConfigFile("100");
stringstream geek(num2);
int y= 0;
geek >> y;
cout << "The value of y is " << y<< "\n";
Supposedly, it should print me number 100 for my int y. But surprisingly, it's printing my previous value which is 120. I am thinking something is wrong in my readConfigFile() method. Can someone guide me through this? How can I get the latest value which is 100?
Actually I just found out the answer that I should add a break; once I already find the key which the code should look like this:
while (getline(drConfig, line))
{
line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end());
if(line[0] == '#' || line.empty()){
continue;
}
auto delimiterPos = line.find("=");
auto name = line.substr(0, delimiterPos);
value = line.substr(delimiterPos + 1);
// Use this to find a specific string
if (line.find(configKey) != std::string::npos) {
cout << value << endl;
break;
}
}
return value;
Basically the break it stops the loop and then it returns me the matching value for the key.
Your code currently always returns the last value in the file. line.find(configKey) != std::string::npos also seems odd, shouldn't it just be configKey == name?
line[0] == '#' || line.empty() has undefined behaviour if you aren't using c++11 or later, its better to swap the two conditions: line.empty() || line[0] == '#'.
Try this code:
string readConfigFile(string configKey) {
cout << "ReadConfigFile\n";
fstream drConfig("/usr/share/dr_config");
if(drConfig.is_open()) {
string line;
while (getline(drConfig, line))
{
line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end());
if(line.empty() || line[0] == '#'){
continue;
}
auto delimiterPos = line.find("=");
if (delimiterPos == std::string::npos) {
return "Invalid config file";
}
auto name = line.substr(0, delimiterPos);
auto value = line.substr(delimiterPos + 1);
// Use this to find a specific string
if (configKey == name) {
return value;
}
}
return "Couldn't find key";
} else {
return "Couldn't open the config file!\n";
}
}

How to read file and save hyphen using STL C++

I have to read text file, convert it to lower case and remove non-alphabetic characters but also need to save hyphen and do not count it as a word. here is my coding. It is counting hyphen as word in UnknownWords . I just want to save hyphen and just only want to count words which are on the left and right side of the hyphen in the .txt.
My output:
110 Known words read
79 Unknown words read //it is because it is counting hyphen as word
Desired output is:
110 Known words read
78 Unknown words read
Code:
void WordStats::ReadTxtFile(){
std::ifstream ifile(Filename);
if(!ifile)
{
std::cerr << "Error Opening file " << Filename << std::endl;
exit(1);
}
for (std::string word; ifile >> word; )
{
transform (word.begin(), word.end(), word.begin(), ::tolower);
word.erase(std::remove_if(word.begin(), word.end(), [](char c)
{
return (c < 'a' || c > 'z') && c != '\'' && c != '-';
}), word.end());
if (Dictionary.count(word))
{
KnownWords[word].push_back(ifile.tellg());
}
else
{
UnknownWords[word].push_back(ifile.tellg());
}
}
// std::string word; ifile >> word;
std::cout << KnownWords.size() << " known words read." << std::endl;
std::cout << UnknownWords.size() << " unknown words read." << std::endl;
}
If you don't want to put a word that's just "-" by itself, check for that before adding to the word vectors:
for (std::string word; ifile >> word; )
{
transform (word.begin(), word.end(), word.begin(), ::tolower);
word.erase(std::remove_if(word.begin(), word.end(), [](char c)
{
return (c < 'a' || c > 'z') && c != '\'' && c != '-';
}), word.end());
if (word.find_first_not_of("-") == string::npos) { // Ignore word that's only hyphens
continue;
}
if (Dictionary.count(word))
{
KnownWords[word].push_back(ifile.tellg());
}
else
{
UnknownWords[word].push_back(ifile.tellg());
}
}

Finding Word + X letters after it

I want to start of by saying that I am still learning and some might think that my code looks bad, but here it goes.
So I have this text file we can call example.txt.
A line in example.txt can look like this:
randomstuffhereitem=1234randomstuffhere
I want my program to take in the numbers that are next to the item= and I have started a bit on it using the following code.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string word;
int main()
{
ifstream readFile("example.txt", ios::app);
ofstream outfile("Found_Words.txt", ios::app);
bool found = false;
long int price;
cout << "Insert a number" << endl;
cout << "number:";
cin >> number;
system("cls");
outfile << "Here I start:";
while( readFile >> word )
{
if(word == "item=")
Here is the problem; first of all it only searchs for "item=" but to find it, it cannot be included with other letters. It has to be a standalone word.
It wont find:
helloitem=hello
It will find:
hello item= hello
It has to be separated with spaces which is also a problem.
Secondly I want to find numbers next to the item=. Like I want it to be able to find item=1234 and please note that 1234 can be any number like 6723.
And I dont want it to find what comes after the number, so when the number stops, it wont take in anymore data. Like item=1234hello has to be item=1234
{
cout <<"The word has been found." << endl;
outfile << word << "/" << number;
//outfile.close();
if(word == "item=")
{
outfile << ",";
}
found = true;
}
}
outfile << "finishes here" ;
outfile.close();
if( found = false){
cout <<"Not found" << endl;
}
system ("pause");
}
You can use a code like this:
bool get_price(std::string s, std::string & rest, int & value)
{
int pos = 0; //To track a position inside a string
do //loop through "item" entries in the string
{
pos = s.find("item", pos); //Get an index in the string where "item" is found
if (pos == s.npos) //No "item" in string
break;
pos += 4; //"item" length
while (pos < s.length() && s[pos] == ' ') ++pos; //Skip spaces between "item" and "="
if (pos < s.length() && s[pos] == '=') //Next char is "="
{
++pos; //Move forward one char, the "="
while (pos < s.length() && s[pos] == ' ') ++pos; //Skip spaces between "=" and digits
const char * value_place = s.c_str() + pos; //The number
if (*value_place < '0' || *value_place > '9') continue; //we have no number after =
value = atoi(value_place); //Convert as much digits to a number as possible
while (pos < s.length() && s[pos] >= '0' && s[pos] <= '9') ++pos; //skip number
rest = s.substr(pos); //Return the remainder of the string
return true; //The string matches
}
} while (1);
return false; //We did not find a match
}
Note that you should also change the way you read strings from file. You can either read to newline (std::getline) or to the end of stream, like mentioned here: stackoverflow question

Most common/idiotproof way to catch invalid input

I am getting into c++ right now, and right now I want to know the most common/best way to catch invalid input. I would love answers to this wide open question, but my more specific question is as follows.
I want a char from the user. If the char is 'y' then it will repeat, if it is 'n' then the program will close. If I enter multiple chars then it will repeat as many times as chars e.g. I enter 'hello' it will show my output 5 times. I assume that it reads each char and goes through the whole loop then reads the next char in line. How can I get it to show up just one time?
bool valid = 0;
while(valid)
{
...
bool secValid = 0;
while(secValid == 0)
{
cout << "To enter another taxable income type 'y': \n\n";
char repeat = NULL;
cin >> repeat;
if(repeat == 'y')
{
valid = 0;
secValid = 0;
system("cls");
}else if(repeat == 'n')
{
return;
}else
{
secValid = 1;
}
}
}
You could structure it something like this:
while(true) {
cout << "Repeat (y/n)? ";
string line;
if(!getline(cin, line))
break; // stream closed or other read error
if(line == "y") {
continue;
} else if(line == "n") {
break;
} else {
cout << "Invalid input." << endl;
}
}
Example session:
Repeat (y/n)? y
Repeat (y/n)? foo
Invalid input.
Repeat (y/n)? n
Here we use std::getline to get a whole line of input, instead of getting one character at a time.
std::getline():
std::string line;
std::getline(std::cin, line);
if (line == "y") {
// handle yes
}
else if (line == "n") {
// handle no
}
else {
// handle invalid input
}
use std::getline from the <string> header to read a line of input into a std::string
Also when checking string for "y" or "n" is good practise to use upcased string instead. For example
std::string YES = "Y";
std::string NO = "N";
...
std::string line;
std::getline(std::cin, line);
std::transform(line.begin(), line.end(), line.begin(), std::toupper);
if (line == YES)
{
...
}
else if (line == NO)
{
..
.
}