Comparing elements of text file between each other - c++

I am trying to compare blocks of three numbers with each other to make a new output file with only the ones that meet that: first digit of the block is less than the second and less than the third, the second digit in the block has to be greater than the first but less than the third.
This is my code for the input file:
int main()
{
ofstream outfile ("test.txt");
outfile << "123 456 789 123 123 432 \n 123 243 " << endl;
I want to split this in blocks of three like"123", "456" and so on to be able to only write only the ones that meet the requirement in the new output file. I decided to conver the whole file into an integer vector to be able to compare them.
char digit;
ifstream file("test.txt");
vector<int> digits;
while(file >> digit) {
digits.push_back(digit - '0');
}
and I suppose that the method that compares them would look something like this:
bool IsValid(vector<int> digits){
for(int i=0; i<digits.size(); i++){
if(digits[0] < digits[1] & digits[0] < digits[2] & digits[1]<digits[2])
return true;
else{
return false;
}
}
}
However this would just compare the first block, would you do it differently? or should I keep doing the vector idea

You can do in this way. The "get" read a single char and when there are 3 digits the function IsValid is called.
#include <fstream>
#include <string>
#include <vector>
using namespace std;
bool IsValid(vector<int> digits)
{
if(digits[0] < digits[1] & digits[0] < digits[2] & digits[1]<digits[2])
return true;
else
return false;
}
int main()
{
ifstream in("test.txt");
ofstream out("output.txt");
char tmp;
vector<int> digits;
while(in.get(tmp))
{
if(tmp!=' ' and tmp!='\n')
{
digits.push_back(tmp-'0');
if(digits.size()==3)
{
if(IsValid(digits))
out<<digits[0]<<digits[1]<<digits[2]<<endl;
digits.clear();
}
}
}
out.close();
in.close();
}

if you task is : first digit of the block is less than the second and less than the third, the second digit in the block has to be greater than the first but less than the third - you num in string type - sorted - use it )) if data is 3 digits and space separeted )))
std::stringstream ss{line}; - for example like fstream )))
#include <iostream>
#include <vector>
#include <iterator>
#include <string>
#include <sstream>
#include <algorithm>
int main() {
std::string line{"123 456 789 123 123 432 123 243 "};
std::cout << line << std::endl;
std::string out_line;
std::stringstream ss{line};
std::string tmp_str;
while(ss >> tmp_str) {
if (std::is_sorted(std::begin(tmp_str), std::end(tmp_str))) {
out_line += tmp_str + " ";
}
}
std::cout << out_line << std::endl;
return 0;
}

Related

How to read a CSV dataset in which each row has a distinct length. C++

I'm just new to C++ and am studying how to read data from csv file.
I want to read the following csv data into vector. Each row is a vector. The file name is path.csv:
0
0 1
0 2 4
0 3 6 7
I use the following function:
vector<vector<int>> read_multi_int(string path) {
vector<vector<int>> user_vec;
ifstream fp(path);
string line;
getline(fp, line);
while (getline(fp, line)) {
vector<int> data_line;
string number;
istringstream readstr(line);
while (getline(readstr, number, ',')) {
//getline(readstr, number, ',');
data_line.push_back(atoi(number.c_str()));
}
user_vec.push_back(data_line);
}
return user_vec;
}
vector<vector<int>> path = read_multi_int("C:/Users/data/paths.csv");
Print funtion:
template <typename T>
void print_multi(T u)
{
for (int i = 0; i < u.size(); ++i) {
if (u[i].size() > 1) {
for (int j = 0; j < u[i].size(); ++j) {
//printf("%d ", u[i][j]);
cout << u[i][j] << " ";
}
printf("\n");
}
}
printf("\n");
}
Then I get
0 0 0
0 1 0
0 2 4
0 3 6 7
Zeros are added at the end of the rows. Is possible to just read the data from the csv file without adding those extra zeros? Thanks!
Based on the output you are seeing and the code with ',' commas, I beleive that your actual input data really looks like this:
A,B,C,D
0,,,
0,1,,
0,2,4,
0,3,6,7
So the main change is to replace atoi with strtol, as atoi will always return 0 on a failure to parse a number, but with strtol we can check if the parse succeeded.
That means that the solution is as follows:
vector<vector<int>> read_multi_int(string path) {
vector<vector<int>> user_vec;
ifstream fp(path);
string line;
getline(fp, line);
while (getline(fp, line)) {
vector<int> data_line;
string number;
istringstream readstr(line);
while (getline(readstr, number, ',')) {
char* temp;
char numberA[30];
int numberI = strtol(number.c_str(), &temp, 10);
if (temp == number || *temp != '\0' ||
((numberI == LONG_MIN || numberI == LONG_MAX) && errno == ERANGE))
{
// Could not convert
}else{
data_line.emplace_back(numberI);
}
}
user_vec.emplace_back(data_line);
}
return user_vec;
}
Then to display your results:
vector<vector<int>> path = read_multi_int("C:/Users/data/paths.csv");
for (const auto& row : path)
{
for (const auto& s : row) std::cout << s << ' ';
std::cout << std::endl;
}
Give the expected output:
0
0 1
0 2 4
0 3 6 7
Already very good, but there is one obvious error and another error in your print function. Please see, how I output the values, with simple range based for loops.
If your source file does not contain a comma (','), but a different delimiter, then you need to call std::getline with this different delimiter, in your case a blank (' '). Please read here about std::getline.
If we then use the following input
Header
0
0 1
0 2 4
0 3 6 7
with the corrected program.
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
vector<vector<int>> read_multi_int(string path) {
vector<vector<int>> user_vec;
ifstream fp(path);
string line;
getline(fp, line);
while (getline(fp, line)) {
vector<int> data_line;
string number;
istringstream readstr(line);
while (getline(readstr, number, ' ')) {
//getline(readstr, number, ',');
data_line.push_back(atoi(number.c_str()));
}
user_vec.push_back(data_line);
}
return user_vec;
}
int main() {
vector<vector<int>> path = read_multi_int("C:/Users/data/paths.csv");
for (vector<int>& v : path) {
for (int i : v) std::cout << i << ' ';
std::cout << '\n';
}
}
then we receive this as output:
0
0 1
0 2 4
0 3 6 7
Which is correct, but unfortunately different from your shown output.
So, your output routine, or some other code, may also have some problem.
Besides. If there is no comma, then you can take advantage of formatted input functions using the extraction operator >>. This will read your input until the next space and convert it automatically to a number.
Additionally, it is strongly recommended, to initialize all variables during definition. You should do this always.
Modifying your code to use formatted input, initialization, and, maybe, better variable names, then it could look like the below.
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
vector<vector<int>> multipleLinesWithIntegers(const string& path) {
// Here we will store the resulting 2d vector
vector<vector<int>> result{};
// Open the file
ifstream fp{ path };
// Read header line
string line{};
getline(fp, line);
// Now read all lines with numbers in the file
while (getline(fp, line)) {
// Here we will store all numbers of one line
vector<int> numbers{};
// Put the line into an istringstream for easier extraction
istringstream sline{ line };
int number{};
while (sline >> number) {
numbers.push_back(number);
}
result.push_back(numbers);
}
return result;
}
int main() {
vector<vector<int>> values = multipleLinesWithIntegers("C:/Users/data/paths.csv");
for (const vector<int>& v : values) {
for (const int i : v) std::cout << i << ' ';
std::cout << '\n';
}
}
And, the next step would be to use a some more advanced style:
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <iterator>
auto multipleLinesWithIntegers(const std::string& path) {
// Here we will store the resulting 2d vector
std::vector<std::vector<int>> result{};
// Open the file and check, if it could be opened
if (std::ifstream fp{ path }; fp) {
// Read header line
if (std::string line{}; getline(fp, line)) {
// Now read all lines with numbers in the file
while (getline(fp, line)) {
// Put the line into an istringstream for easier extraction
std::istringstream sline{ line };
// Get the numbers and add them to the result
result.emplace_back(std::vector(std::istream_iterator<int>(sline), {}));
}
}
else std::cerr << "\n\nError: Could not read header line '" << line << "'\n\n";
}
else std::cerr << "\n\nError: Could not open file '" << path << "'\n\n'";
return result;
}
int main() {
const std::vector<std::vector<int>> values{ multipleLinesWithIntegers("C:/Users/data/paths.csv") };
for (const std::vector<int>& v : values) {
for (const int i : v) std::cout << i << ' ';
std::cout << '\n';
}
}
Edit
You have shown your output routine. That should be changed to:
void printMulti(const std::vector<std::vector<int>>& u)
{
for (int i = 0; i < u.size(); ++i) {
if (u[i].size() > 0) {
for (int j = 0; j < u[i].size(); ++j) {
std::cout << u[i][j] << ' ';
}
std::cout << '\n';
}
}
std::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;
}

Inserting integers from a text file to an integer array

I have a text file filled with some integers and I want to insert these numbers to an integer array from this text file.
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ifstream file("numbers.txt");
int nums[1000];
if(file.is_open()){
for(int i = 0; i < 1000; ++i)
{
file >> nums[i];
}
}
return 0;
}
And, my text file contains integers line by line like:
102
220
22
123
68
When I try printing the array with a single loop, it prints lots of "0" in addition to the integers inside the text file.
Always check the result of text formatted extraction:
if(!(file >> insertion[i])) {
std::cout "Error in file.\n";
}
Can it be the problem is your text file doesn't contain 1000 numbers?
I'd recommend to use a std::vector<int> instead of a fixed sized array:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main(){
ifstream file("numbers.txt");
std::vector<int> nums;
if(file.is_open()){
int num;
while(file >> num) {
nums.push_back(num);
}
}
for(auto num : nums) {
std::cout << num << " ";
}
return 0;
}

how to read line and change to integer numbers fstream

I am new to programming and I have a data.txt file with the following content:
bumbumbow
1 0 3 9 8
bumbumbum
1 0 3 9 :0
I want to read the line 2: 1 0 3 9 8 and to turn it into integer numbers but I have an error.
What is the problem? Here is my code:
#include <iostream>
#include <fstream>
#include <limits>
#include<string>
#include<vector>
std::fstream& GotoLine(std::fstream& file, unsigned int num) {
file.seekg(std::ios::beg);
for (int i = 0; i < num - 1; ++i) {
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return file;
}
int main() {
int result, i = 0;
std::vector<int> Array;
using namespace std;
std::fstream file("data.txt");
GotoLine(file, 2);
std::string line2;
std::getline(file, line2);
for (int result; std::getline(file, line2); result = std::stoi(line2))
{
Array.push_back(result);
std::cout << "Read in the number: " << result << "\n\n";
}
return 0;
}
thanks in advance guys
The crash occures due to calling std::stoi() with a wrong parameter "1 0 3 9 8".
You need to replace std::getline(file, line2); result = std::stoi(line2) inside the for loop with something splitting line2 into tokens and calling std::stoi() for those tokens. You can see how to split, for example, here:
Right way to split an std::string into a vector<string>