printing error message after third substring is found - c++

Hello I am pretty new to C++. I have a question regarding the splitting of a string.
For example, I have a string like this
std::string str = "jump 110 5";
and between strings "jump", "110" and "5" can be as many spaces as there can be.
I want to save 110 in an int variable and if after the number 110 another number or character should appear then the loop should break.
So far I have removed all the spaces and saved 110 in a variable and printed it out and the number five get ignored.
How can I break or print an error message after 110 saying that the string is not valid?
Here's my code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
int main() {
std::string str = "jump 110 5";
size_t i = 0;
for ( ; i < str.length(); i++ ){ if ( isdigit(str[i]) ) break; }
str = str.substr(i, str.length() - i );
int id = atoi(str.c_str());
std::cout<<id;
return 0;
}

EDIT: Second attempt..
Here is what I wrote to parse the values into a vector. if the vector has more than one set of numbers, it prints and error.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
int main() {
std::string str = "jump 110 5";
size_t i = 0;
for (; i < str.length(); i++)
{
if (isdigit(str[i]))
break;
}
str = str.substr(i, str.length() - i);
// Parse str to id
std::stringstream sstr;
sstr << str;
std::string tempStr;
std::vector<size_t> id;
while (std::getline(sstr, tempStr, ' '))
{
std::cout << tempStr << std::endl;
id.push_back(std::stoi(tempStr));
}
// print an error if additional numbers are in id
if (id.size() > 1)
{
std::cout << "Error: " << id[1];
}
else
{
std::cout << "You're good";
}
return 0;
}
Caution: There is an error if there are more than one spaces between 110 and 5.
Original Answer:
If you want id to have the value 110 5, then id shouldn't be an int type because it can't contain spaces. If you want id to have the value 1105, then you'll need to get rid of the spaces in the string "110 5" before assigning it to id, otherwise the value will be truncated when assigned to id.
This is what I did to get rid of the spaces to make id equal to 1105.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
int main() {
std::string str = "jump 110 5";
size_t i = 0;
for (; i < str.length(); i++)
{
if (isdigit(str[i]))
break;
}
str = str.substr(i, str.length() - i);
// get rid of spaces
std::string tempStr;
for (int i = 0; i < str.length(); i++)
{
if (str[i] != ' ')
{
tempStr.push_back(str[i]);
}
}
// Set the str object to tempStr
str = tempStr;
int id = atoi(str.c_str());
std::cout << id;
return 0;
}
If you really need to keep id as an int and make 110 and 5 separate, then I'd suggest making id into a std::vector and parse the string into the vector.

Related

Find all substring in a given string c++

I've got a problem with a program which finds all substring in a given string.
I've tried to make variable "found", which would contain a position of a previously found substring and then start searching from the position.
Here's my code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
string str1;
cin >> str >> str1;
int i = 0;
int found = -1;
while(found < str1.size()){
found = str1.find(str, found + 1);
cout<<str1.find(str, found)<<endl;
i++;
}
}
for the following input: "ab
aabb"
it doesn't print anything.
Could you help?
So a little bit of theory first:
substr(a,b) -> returns cut out of the string from position a to position b
find(a) -> returns the position of found character or set of characters 'a'. returns -1 if NOT found.
Let's examine your code:
#include <iostream>
#include <string> //not really needed here. string should already be usable
using namespace std; //in small programs is ok but with big programs this could lead to problems with using specific things that could have the same names in std and other library. So its best to avoid this and or any other using namespace you use.
int main()
{
string str; // you should really name your variables better
string str1;
cin >> str >> str1; // your variable names are unreadable at first glance
int i = 0; // iterator cool but why is it needed if you're just using find()
int found = -1; // good variable although the name "pos" would probably be better as to further explain to the programmer what the variable does
while(found < str1.size()){ //not really sure what you were going for here
found = str1.find(str, found + 1); // this could have been your while logic above instead
cout<<str1.find(str, found)<<endl; // this finds the exact same position again using more resources. your variable found stores the position so doing cout << found << here would be better
i++;
}
}
Now let's see why your code doesn't show anything on console:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
string str1;
cin >> str >> str1; //you input ab as str and abbb as str1
int i = 0;
int found = -1;
while(found < str1.size()){ //first iteration is while(-1 < 4)
found = str1.find(str, found + 1); //<-- find needs just 1 parameter. heres your problem
cout<<str1.find(str, found)<<endl;
i++;
}
}
str1.find("ab); -> function find searches for "ab" in string str1. You don't need to add where it's meant to search for. Also the fact that your while loop is dependant on found < str1.size() and not anything to do with your iterator means your loop will go on forever. whenever this happens most IDE's crash your program giving you nothing cout'ed.
Fix:
#include <iostream>
using namespace std;
int main()
{
string str;
string str1;
int pos;
cin >> str >> str1;
for(int i = 0; i < str1.size(); i++) // this or could be while(true)
{
pos = str1.substr(i).find(str); //finds your string in the rest of the line
if (pos == -1)
{
//NOT FOUND
break; //stops
}
else
{
//FOUND
cout << pos + i << endl; //pos is position in the cut out after adding i we get global position
i += pos; // skip characters after we found them to NOT be found again
}
}
}
Another possible solution would be:
Walk the input string until the point you know the substring cannot fit anymore.
For each input string position, check if each substring starts with the substring (starts_with only since C++20).
[Demo]
#include <iostream>
#include <string>
int main() {
std::string str{ "ab aab" };
std::string sub{ "ab" };
int count{};
size_t last_index{ str.size() > sub.size() ? str.size() - sub.size() : 0 };
for (size_t i{0}; i <= last_index; ++i) {
if (str.substr(i).starts_with(sub)) {
count++;
}
}
std::cout << count;
}
// Outputs: 2
int find_substr(string substr, string str) {
int postion = 0;
auto beginning = str.c_str();
int i = 0;
char* p = (char *)beginning;
while (p && '\0'!=p)
{
p = strstr(p, substr.c_str());
if (!p)
break;
cout << "A substring is at index:" << p - beginning << "\n";
p++;
};
return 0;
}
void test()
{
string substr, str;
{
substr = "ab"; str = "aabb";
cout << "Finding " << substr << " in " << str << "\n";
find_substr(substr, str);
cout << "\n";
}
{
substr = "ab"; str = "abab";
find_substr(substr, str);
cout << "\n";
}
{
substr = "a"; str = "11111111111111111111111a";
find_substr(substr, str);
cout << "\n";
}
}

printing only those strings that include 2-digit number

printing only those strings that include 2-digit number
the text inside "myFile.txt is
{the pink double jump 34
the rising frog 2
doing the code 11
nice 4 }
"
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <algorithm>
int main()
{
std::string path = "myFile.txt";
std::ifstream de;
de.open(path);
if (!de.is_open()) {
std::cout << "nah";
}
else {
std::cout << "file is opened";
std::string str;
while (!de.eof()) {
std::getline(de, str);
for (int i = 0; i < str.length(); i++) {
int aa = 10;
if (str[i] > aa) {
str = "0";
}
}
std::cout << str << "\n\n";
}
}
}
what am I doing wrong? how can I check if there is any 2-digit number inside the string?
You could use stoi as follows:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::ifstream inp("test.txt");
std::string word;
std::vector<std::string> listOfTwoDigitStrings;
while(inp>>std::ws>>word) {
if(word.length() == 2) {
int num = std::stoi(word);
if(num >= 10 && num <= 99) {
listOfTwoDigitStrings.push_back(word);
}
}
}
for(const auto& word: listOfTwoDigitStrings) {
std::cout<<word<<' ';
}
std::cout<<'\n';
return 0;
}
which has the output
34 11
when test.txt contains
{the pink double jump 34
the rising frog 2
doing the code 11
nice 4 } "
P.S.: As you're looking for strings, just read in strings rather than lines and then reading off strings from that line. Reading off strings just makes it simpler since it boils down to just narrowing down to 2-digit strings and then just verifying whether they are numbers or not. Also, as mentioned in the comments, refrain from !file.eof() code.

Need to separate numbers from a string on a line, separated by ';', (25;16;67;13) in c++

We have a string (25;16;67;13;14;.......)
We need to print out the numbers separately. The last number does not have a semicolon behind it.
Output should be something like that:
25
16
67
13
14
......
Assuming we are using str.find, str.substr and size_t variables current_pos, prev_pos, what will be the condition of the while loop we are using to browse the line, so that it prints out all the numbers, not just the first one?
You can make use of std::istringstream:
#include <sstream>
#include <iostream>
int main() {
std::string text("25;16;67;13;14");
std::istringstream ss(text);
std::string token;
while(std::getline(ss, token, ';'))
{
std::cout << token << '\n';
}
return 0;
}
Running the above code online results in the following output:
25
16
67
13
14
If you need only to print the numbers in the string (rather than represent them in data structures) the solution is quite easy. Simply read the entire string, then print it character by character. If the character is a semicolon, print a new line instead.
#include <iostream>
#include <string>
using namespace std;
int main(){
string input;
cin >> input;
for(int i = 0; i < input.length(); i++){
if(input.at(i) == ';') cout << endl;
else cout << input.at(i);
}
}
using namespace std;
int main() {
string a{ "1232,12312;21414:231;23231;22" };
for (int i = 0; i < a.size(); i++) {
if (ispunct(a[i])) {
a[i] = ' ';
}
}
stringstream line(a);
string b;
while (getline(line, b, ' ')) {
cout << b << endl;
}
}
//any punctuation ",/;:<>="
I will give you an exact answer to your question with an example and an alternative solution with an one-liner.
Please see
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <regex>
const std::regex re(";");
int main() {
std::string test("25;16;67;13;14;15");
// Solution 1: as requested
{
size_t current_pos{};
size_t prev_pos{};
// Search for the next semicolon
while ((current_pos = test.find(';', prev_pos)) != std::string::npos) {
// Print the resulting value
std::cout << test.substr(prev_pos, current_pos - prev_pos) << "\n";
// Update search positions
prev_pos = current_pos + 1;
}
// Since there is no ; at the end, we print the last number manually
std::cout << test.substr(prev_pos) << "\n\n";
}
// Solution 2. All in one statement. Just to show to you what can be done with C++
{
std::copy(std::sregex_token_iterator(test.begin(), test.end(), re, -1), {}, std::ostream_iterator<std::string>(std::cout, "\n"));
}
return 0;
}

Detecting if input string has a space

I wrote this code to detect if an input string has a space or not. Please tell what is wrong in this approach.
#include <iostream>
#include <string>
using namespace std;
int main(){
string inp;
getline(cin, inp);
for (int i = 0; i < inp.length(); i++) {
string z = to_string(inp[i]);
if (z == " ") {
cout << "space";
}
else {
i++;
}
}
}
If i enter a string with spaces, it doesn't print "space".
Since inp is an std::string, inp[i] will be a char. Since std::to_string only has overloads for arithmetic, non-char values, calling it on a char is akin to calling it on the integer representation of said char. (If you log z, you'll likely find a number printed.)
Instead, directly compare inp[i] to a space. else { i++; } is also unnecessary – you may be jumping over spaces.
for (int i = 0; i < inp.length(); i++) {
if (inp[i] == ' ') { // note single quotes for char
cout << "space";
}
}
#TrebledJ's answer explains why your code is broken and how to fix it.
Another way to handle this situation is to use std::string::find() instead:
#include <iostream>
#include <string>
int main(){
std::string inp;
std::getline(std::cin, inp);
if (inp.find(' ') != std::string::npos) {
std::cout << "space";
}
}
Alternatively, your original code tries to output "space" for each space character found. You could use find() in a loop:
#include <iostream>
#include <string>
int main(){
std::string inp;
std::getline(std::cin, inp);
std::string::size_type idx = inp.find(' ');
while (idx != std::string::npos) {
std::cout << "space at " << idx << std::endl;
idx = inp.find(' ', idx+1);
}
}

C++ Vector iteration failing for single element input

I am trying to get a txt file with entries part1/1 part2/4 etc... from user and store in vectors "part_name" and "rev_id". So "part_name" contains part1 part2 ... and "rev_id" contains 1 4.....
The program is run as program.exe list.txt in command prompt.
The program works fine when the txt file has 2 or more inputs , but when it has single input the vector size is shown as 2 (but must be 1).
i.e.
if list.txt contains part1/1 part2/4 => part_name.size() is 2
if list.txt contains part1/1 => part_name.size() is still 2.
Can someone help me resolve this ?
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main(int argc, char*argv[])
{
std::string s ;
std::string delimiter = "/";
size_t pos;
std::vector<std::string> part_name;
std::vector<std::string> rev_id;
std::string token1,token2;
ifstream readFile (argv[1]);
if (readFile.is_open())
{
while (!readFile.eof())
{
readFile >> s;
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}
}
}
else{
std::cout<<"Cannot open file"<<endl;
}
readFile.close();
for (unsigned j=0; j < part_name.size(); j++)
{
cout<<part_name.size()<<endl;
cout<<"part name j is " <<part_name[j]<<endl;
cout<<"part id j is " <<rev_id[j]<<endl;
}
}
I think the problem lies here
while (!readFile.eof())
{
readFile >> s;
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}
change above to
while (readFile >> s)
{
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}
Your last read is probably not reading anything. Try:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main(int argc, char*argv[])
{
std::string s ;
std::string delimiter = "/";
size_t pos;
std::vector<std::string> part_name;
std::vector<std::string> rev_id;
std::string token1,token2;
ifstream readFile (argv[1]);
if (readFile.is_open())
{
while( ( readFile >> s ).good() )
{
std::cerr << "Field '" << s << "' and " << readFile.good() << std::endl;
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, pos);
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}
}
}
else {
std::cout<<"Cannot open file"<<endl;
}
readFile.close();
for (unsigned j=0; j < part_name.size(); j++)
{
cout<<part_name.size()<<endl;
cout<<"part name j is " <<part_name[j]<<endl;
cout<<"part id j is " <<rev_id[j]<<endl;
}
}
eof() returns true not when the file position is at the end, but after you attempt a read at the end of the file. So the first time in the loop you consume the input up to the eof (not included). Now eof() is false. For this reason the loop is entered again and this time the extractor (>>) hits the end of file. The read operation fails and the string is not changed (that's why you see the same values twice).
A better (and more idiomatic to modern C++) way to code is by using stream iterators
#include <iterator>
// [...]
std::istream_iterator<std::string> scan( readFile );
std::istream_iteartor<std::string> eof;
while( scan != eof )
{
s = *scan++;
// s is your string
}
Also it would be better to have the loop in the second part to run from 0 upward, since elements in vectors are numbered starting from 0.
There are some lines than make me suspicious..
Why start your iteration loop by the index 1 ?
for (unsigned j=1; j < part_name.size(); j++)
{
cout<<part_name.size()<<endl;
cout<<"part name j is " <<part_name[j]<<endl;
cout<<"part id j is " <<rev_id[j]<<endl;
}
You always skip the first element of yours vectors.