I need a little bit help with my code. The first part of the code, was easy to create. Read from two textfiles -> Output in a new textfile.
My next step is to compare the both outputs line by line.
If the number is the same, the numbers stays.
If the number is different to the number of textfile2,
the number with be replaced.
Example:
Textfile1:
2221112221
1122221112
2222221111
1111111111
Textfile2:
2222221111
2211222212
1111111111
2221112222
Result that should happen on Textfile3:
(like I'm overlapping textfile2 on textfile1)
2222221111
2211222212
1111111111
2221112222
So I already researched for str.compare, but I'm not able to output the result as above stated. I don't know if this works with it.
if((line2.compare(0, line2.length(), line1)) == 0)
string line1, line2;
ifstream read1, read2;
read1.open("test.txt", ios::in);
read2.open("test2.txt", ios::in);
ofstream outFile("outputfile.txt", ios::out | ios::app);
if(!read1 || !read2){
cerr << "One file is missing" << endl;
exit(1);
}
else {
while(getline(read1, line1))
{
outFile << line1;
}
while(getline(read2, line2))
{
outFile << line2 << endl;
}
Thanks a lot guys!
iterate the strings and compare character vs. character? This would allow you to achieve what you're looking for.
This example obviously does not have exception handling (e.g. different string lengths):
std::string corn = "I eat Corn!";
std::string rice = "I eat Rice!";
int main()
{
for (size_t i = 0; i < corn.length(); i++)
{
if (corn[i] != rice[i])
{
rice[i] = corn[i];
}
}
std::cout << rice;
}
Related
i am trying to get my file to remove the leading and trailing space but it does not work.
this is the txt file contents:
392402 wench
I have tried printing out my code, and this is what is displayed.
first: 392402 wench second:
I want it to display this instead
first: 392402 second: wench
this is my code
void readFile(const string &fileName) {
int limit;
ifstream ifs(fileName);
string::size_type position;
key_type item;
mapped_type count;
string line;
if (ifs.is_open()) {
ifs >> limit;
for (int i = 0; i < limit; i++) {
getline(ifs, line);
position = line.find(" ", 0);
auto c = line.substr(position + 1);
item = line.substr(0, position);
cout << "first: " << c << " second: " << item << endl;
value_type value(item, count);
values.push_back(value);
}
} else {
cout << "Can't open file.";
}
what am i doing wrong? Thank you
The two biggest mistakes you're making are (a) not checking your values for expected output as you go, and (b) not running your code in a debugger to see what is really happening. If you had, the values of position, c, and item would have been blatantly wrong, and you could then surmise where to go from there.
Belaying the highly-likely possibility that the loop iteration is broken from inception because you never consumed the remainder of the entry line containing input, let's look at the actual data and what you're asking of it with your code.
We read this entire line:
392402 wench
You then ask "find the first single-space string in this line" via this code:
position = line.find(" ", 0);
Well, that would be here:
392402 wench
^here
So position is zero (0). You then ask for the sub-string, starting a that position + 1, through the end of the string with this code:
auto c = line.substr(position + 1);
Therefore c now contains (leading space removed via the +1):
392402 wench
Now we build item, which is done with this line:
item = line.substr(0, position);
Remember, position is zero, so you're asking for the string, starting at location 0, length 0. As you can imagine, that isn't going to amount to anything. So now item is an empty string.
Finally, the output statement:
cout << "first: " << c << " second: " << item << endl;
will produce:
first: 392402 wench second:
I.e. exactly what you're seeing. And that's it. Clearly this is wrong.
Alternative
Use better error checking, value checking, and a string stream for per-line extraction. The following code doesn't give two cents about your type aliases (mainly because you didn't include them anyway and I'd rather not loft any guesses as to their origin).
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <limits>
// Expects a file with the following format:
// count
// name1 value1
// name2 value2
// ...
void readFile(const std::string &fileName)
{
std::ifstream ifs(fileName);
if (ifs.is_open())
{
int limit;
if (ifs >> limit && limit > 0)
{
// consume through end of line.
ifs.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// repeat until `limit` iterations or stream error/eof
std::string line;
for (int i = 0; i < limit && std::getline(ifs, line); i++)
{
std::istringstream iss(line);
// extract line values. Note these *can* be formatted
// extraction for things besides just strings
std::string first, second;
if (iss >> first >> second)
{
std::cout << "first: " << first << " second: " << second << '\n';
// TODO: whatever you want to do with first/second
}
}
}
ifs.close();
}
else
{
std::cerr << "Can't open file: " << fileName << '\n';
}
}
Note: The above code will NOT work for remaining-line-content as the expected second value. E.g. It will not process something like this as you may first expect:
10000 this is a multi-word description
will produce this:
first: 10000 second: this
which is considerably different than what you may be expecting:
first: 10000 second: this is a multi-word description
There was no suggestion in the original post such support was mandatory, though adding it wouldn't be terribly difficult to add. If it is a requirement, I leave that task to you.
As part of my assignment I need to open a file and then read the information into 3 arrays. These information are separated into 3 different columns first one is, Country Code name(is string), second is the population(is int) and the third is the full name of the country. Here is the example of few lines of the file:
AU 20090437 Australia
BR 186112794 Brazil
BU 7262675 Bulgaria
CA 32805041 Canada
CN 1306313812 China
DO 8950034 Dominican Republic
So far I have:
void readCntrData(string [], int [], string[], int &size, const int maxSize);
int main()
{
const int COUNTRIES = 200;
// maximum size of arrays
int size = 0;
string cntrCodes[COUNTRIES];
int cntrPopulation[COUNTRIES];
string cntrNames[COUNTRIES];
string inputFileName = "countries.txt";
ifstream inputFile;
inputFile.open(inputFileName.c_str());
if (inputFile.fail())
{
cout << "\n\tPlease check the name of the input file and \n\ttry again later!\n";
exit(EXIT_FAILURE);
}
int index = 0;
while (index < COUNTRIES && inputFile >> cntrCodes[index] >> cntrPopulation[index] >> cntrNames[index] ) {
index++;
}
size = index;
if (size == COUNTRIES && !inputFile.eof()){
cout << "\n\tThe input file \"" << inputFileName <<
"\"is too big: \n\tit has more than " << COUNTRIES << " items!\n";
exit(EXIT_FAILURE);
}
inputFile.close();
}
The issue here few countries have two part names, and my code breaks where the name of country has two parts. I don't know how to ignore the space there and read the whole name.
I appreciate any feedback.
Just cleaning the code up a bit...
the main problem you ask about in your question has already been addressed by user4581301 in comments: summarily, using getline to read the country code will cope with having one or more whitespace-separated words
since C++11, we've been able to use the ifstream constructor to open a filename passed in a std::string, and it's often convenient to construct the ifstream inside an if/else construct that then handles the successful-open and failed-attempt-to-open cases
there's no need to explicitly close ifstreams that are going out of scope anyway
it's good to send error messages to std::cerr, so if someone running your program does something like "theprogram > theprogram.output" they'll still see the error messages in their terminal
no real need to have separate index and size variables, and something like num_countries is a better, more meaningful name
checking for EOF is a bit of a dark art - I wouldn't recommend using inputFile.eof() the way you did because if the last country read was followed by an empty line in the file, you wouldn't have hit end-of-file even though it's "logically" empty thereafter; it's too easy for someone not to notice empty lines at the end of a file when they're working in a editor to create/update the file; checking if there's another non-whitespace character is a more robust approach
the common size for int these days is 32 bits, which can handle numbers up to a couple billion (when signed, or a bit over 4 billion for unsigned int); China's population's a bit too close to that for comfort - if you want to write code in a way that should still work 20 or 50 years hence, it's good to think about whether the types will still be large enough to store the values; int64_t from <cstdint> is a better choice.
Revised code:
int main()
{
const int COUNTRIES = 200;
string cntrCodes[COUNTRIES];
int64_t cntrPopulation[COUNTRIES];
string cntrNames[COUNTRIES];
string inputFileName = "countries.txt";
if (std::ifstream inputFile{inputFileName})
{
int num_countries = 0;
while (num_countries < COUNTRIES &&
inputFile >> cntrCodes[num_countries] >> cntrPopulation[num_countries] &&
getline(std::cin, cntrNames[num_countries]))
++num_countries;
// will see if we can read another character (remember >> skips
// whitespace by default), rather than check inputFile.eof()
// which may not be true if there're any extra empty lines after
// the data...
char character;
if (num_countries == COUNTRIES && inputFile >> character)
{
std::cerr << "\n\tThe input file \"" << inputFileName <<
"\"is too big: \n\tit has more than " << COUNTRIES << " items!\n";
exit(EXIT_FAILURE);
}
// any extra code to actually use the country data goes here...
}
else
{
std::cerr << "\n\tPlease check the name of the input file and \n\ttry again later!\n";
exit(EXIT_FAILURE);
}
}
For the last input of each line, you can use getline which reads everything until it meets an Enter key.
You can try this:
while (index < COUNTRIES && inputFile >> cntrCodes[index] >> cntrPopulation[index] ) {
getline (inputFile, cntrNames[index]);
index++;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I'm still new to c++(and to stackoverflow).
I'm creating program to analyze some data for me(open file, save data into vectors, then I search vectors for name, and then I work with objects functions). Anyways, previous "version" of the program works fine, but file that I open only contains 1 string per line in the beginning(followed by other data), so it's easy to work with.
What I'm trying to do, is to open up the files that contain 1-3 strings(i.e. line 1 - West Ham United, line 2 - Everton etc.). After the name, other data follows on the same line.
I thought about separating the name and other data into 2 lines, in example Line1 - name, Line2 - other data, and so on. But how do I save the whole "name" line into vector(vector is of the object type). Other option would be to open up the file and saving all of the chars into an array. Afterwards I would output that array in Outfile, deleting the spaces only between letters(i.e. - WestHamUnited), and then I would work with the output file.
Question is, how do I delete the spaces only between letters?
Maybe you guys could recommend some other option that I'm not aware of.
Let's suppose there is text line stored in string object (s can be read from file/stream by getline)
std::string s = "Manchester City 17 26 2.16";
and we need to read all text before the first number to other string (join some words without spaces)
std::string name = ""; // empty string to store name
We do not know how many non-numbers (parts of name) will be until the first number is in the string, but we expect that number is.
If your task is something like that, consider the following example:
std::istringstream ss(s); // creation of stream object to read data from text line
double d = 0; // will be the first number
std::string str; // buffer string for parts of name
bool notNumber;
// loop that works to update name trying to find a number
do{
ss >> d; // try to read number
notNumber = ss.fail(); // save the state (if number was read value is false)
if (notNumber) // is value is true (not a number is the first in the stream)
{
ss.clear(); // reset the state
ss >> str; // read a word
name.append(str); // add this word to the name
}
} while (notNumber && !ss.eof()); // while non-numbers are read and stream is not empty
// after loop we have name and, perhaps, number
std::cout << "Name is: " << name << std::endl;
std::cout << "The first number is: " << d << std::endl;
UPDATE:
Actually we can use notNumber to know that number was really present in the initial string s
if (notNumber)
std::cout << "There is no number after name!" << std::endl;
else
std::cout << "The first number is: " << d << std::endl;
UPDATE 2:
For file test.txt comprising
West Ham United 3.14 22
Everton 17 26 2.16
Manchester City 9.32 17 26
the following program
#include <map>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
using namespace std;
int main(void)
{
// data structure to store data from file
map<string, vector<double>> dataTable;
// open the file
ifstream inFile("test.txt");
if (!inFile.is_open())
{
cout << "File error!" << endl;
return 1;
}
// reading data from file
while (!inFile.eof() && inFile.good())
{
string s;
string name;
getline(inFile, s);
istringstream ss(s);
double d = 0;
string str;
bool notNumber;
do{
ss >> d;
notNumber = ss.fail();
if (notNumber)
{
ss.clear();
ss >> str;
name.append(str);
}
} while (notNumber && !ss.eof());
if (name.length() == 0)
continue;
// saving numbers to table
do{
dataTable[name].push_back(d);
ss >> d;
} while (!ss.fail());
}
inFile.close();
// print data stored in table
for (map<string, vector<double>>::iterator i = dataTable.begin(); i != dataTable.end(); i++)
{
cout << i->first << " : ";
for (vector<double >::iterator j = i->second.begin(); j != i->second.end(); j++)
{
cout << *j << " ";
}
cout << endl;
}
return 0;
}
provides the following output:
"Question is, how do I delete the spaces only between letters?"
You are aware of std::string, aren't you? Then you should be able to locate a method that deletes a character or character range from the string.
Good. Than the only problem would be how to detect if a character is a space. How hard could it be, I wonder.
I short: RTFM, Luke, use it with full confidence.
If you can control input file format, I would recommend you to introduce some delimiter mark for the first column.
Otherwise, if the number of columns is fixed, you can read line in reverse. E.g. the latest 3 words are numbers and all the rest is team's name.
Note, that it is wrong just read words until the first digit, because there are exist teams with numbers in name (e.g. FC Schalke 04).
Here is an example:
struct FileLine
{
std::string col1;
double col2 = 0., col3 = 0., col4 = 0.;
// `words` is a vector of words from a line in file
bool load(const std::vector<std::string>& words)
{
col1.clear();
col2 = col3 = col4 = 0.;
std::vector<std::string>::size_type n = words.size();
if (n >= 4) {
col4 = std::stod(words.at(n-1));
col3 = std::stod(words.at(n-2));
col2 = std::stod(words.at(n-3));
col1 = std::accumulate(words.begin(), words.end()-3, col1);
}
return n >= 4;
}
};
Another way is to use regular expressions (link). It's very powerful tool for a text parsing.
While reading in data from a separate text file, it doesn't keep the spaces and instead looks comes out looking like :
Todayyouareyouerthanyou,thatistruerthantrue
When it should have the spaces and say:
Today you are youer than you, that is truer than true
Here is my code that I have so far:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
std::ifstream inFile;
inFile.open("Rhymes.txt", std::ios::in);
if (inFile.is_open())
{
string word;
unsigned long wordCount = 0;
while (!inFile.eo())
{
cout << word;
inFile >> word;
if (word.length() > 0)
{
wordCount++;
}
}
cout << "The file had " << wordCount << " word(s) in it." << endl;
}
system("PAUSE");
return 0;
}
The "Rhymes.txt" has many phrases such as the one above and I'll just add 2 more so it's not a lot on here. Here they are:
Today you are You, that is truer than true. There is no one alive who is Youer than You.
The more that you read, the more things you will know. The more that you learn, the more places you'll go.
How did it get so late so soon? Its night before its afternoon.
Any help or advice would be greatly appreciated!! Also I am a beginner so if this turns out to be something really obvious, sorry!
How about inserting the spaces back to your output, so instead of this
cout << word;
You put this:
cout << word << " ";
Another option would be to read whole lines from your input file and then split them to words.
Issues that I see:
You are writing out word before the first read.
Reading the words using inFile >> word skips the white spaces. You need to add code to write the white spaces.
I am not sure what you were thinking with the following block of code. But, it is not necessary.
if (word.length() > 0)
{
wordCount++;
}
You can simplify your while loop to:
while (inFile >> word)
{
cout << word << " ";
wordCount++;
}
This will print an extra white space at the end. If that is objectionable, you can add more logic to fix that.
Let's fix the typo: inFile.eo() -> inFile.eof() and include stdlib.h for system(). Now you can put the spaces back by writing cout << word << " ";
But your program seems to be out by 1. Linux wc says 53 words but your program says 54. So I fixed your loop like this:
while (true)
{
inFile >> word;
if (inFile.eof())
break;
if (word.length() > 0)
{
wordCount++;
cout << word << " ";
}
}
Now it agrees with wc.
I'm trying to read a text file to find how many times a phrase/sentence(/substring?) occurs. I've done a real bodge job on it currently (see code below) but as you'll see, it relies on some rather clunky if statements.
I don't have access to the files I''ll be using it on at home, so I've used a file called big.txt and search for phrases like "and the" for the time being.
Ideally, I'd like to be able to search for "this error code 1" and it return the number of times it occurs. Any ideas on how I might get my code to work that way would be incredibly useful!
int fileSearch(string errorNameOne, string errorNameTwo, string textFile) {
string output; //variable that will store word from text file
ifstream inFile;
inFile.open(textFile); //open the selected text file
if (!inFile.is_open()) {
cerr << "The file cannot be opened";
exit(1);
}
if (inFile.is_open()) { //Check to make sure the file has opened correctly
while (!inFile.eof()) { //While the file is NOT at the end of the file
inFile >> output; //Send the data from the file to "output" as a string
if (output == errorNameOne) { //Check to look for first word of error code
marker = 1; //If this word is present, set a marker to 1
}
else if (marker == 1) { //If the marker is set to 1,
if (output == errorNameTwo) { //and if the word matches the second error code...
count++; //increse count
}
marker = 0; //either way, set marker to 0 again
}
}
}
inFile.close(); //Close the opened file
return count; //Function returns count of error
}
Given that your phrase can only occur once per line and the number follows the phrase after a number of spaces you can read the file line by line and use std::string::find() to see of your phrase is somewhere in the line. That will return the position of the phrase. You can then work on checking the rest of the line immediately after the phrase to test the number for 1 or 0.
This code may not be exactly what you want (still not certain of the exact specs) but hopefully it should contain enough examples of what you can do to achieve your goal.
// pass the open file stream in to this function along with the
// phrase you are looking for and the number to check
int count(std::istream& is, const std::string& phrase, const int value)
{
int count = 0;
std::string line;
while(std::getline(is, line)) // read the stream line by line
{
// check if the phrase appears somewhere in the line (pos)
std::string::size_type pos = line.find(phrase);
if(pos != std::string::npos) // phrase found pos = position of phrase beginning
{
// turn the part of the line after the phrase into an input-stream
std::istringstream iss(line.substr(pos + phrase.size()));
// attempt to read a number and check if the number is what we want
int v;
if(iss >> v && v == value)
++count;
}
}
return count;
}
int main()
{
const std::string file = "tmp.txt";
std::ifstream ifs(file);
if(!ifs.is_open())
{
std::cerr << "ERROR: Unable to open file: " << file << '\n';
return -1;
}
std::cout << "count: " << count(ifs, "Header Tangs Present", 1) << '\n';
}
Hope this helps.