finding a word from a file and substitution into other file - c++

I have two text files like these:
11.txt:
1 5.66
2 4.95
3 2.55
4 0.99
5 2.87
NB.txt:
1 2 3 4 5
4 5 3 2 1
3 4 5 1 2
I have written the below code to fine, for example, "1" from File 1, and search it in File 2, then substitute "1" with "5.66". and repeat it for other numbers, i.e. 2,3,4,5. but I don't know why it doesn't work. additionally, it doesn't read the first line of 11.txt.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
string line;
double AtomId, Atom_radius,search ;
ifstream AtomId_file ("11.txt");
string namefile;
if (AtomId_file.is_open()){
for (int linenox = 0; getline (AtomId_file,line) && linenox < 6; linenox++){
if (linenox == 0) AtomId_file>>AtomId>>Atom_radius;
}
cout<<"AtomId: "<<AtomId<<" Atom_radius: "<<Atom_radius<<endl;
cout<<namefile<<"\n";
}
ifstream NB("NB.txt");
size_t pos;
if (NB.is_open())
{
search = AtomId;
getline(NB,line);
pos=line.find(search);
if(pos!=string::npos)
{
search = Atom_radius;
cout <<"Found!";
}
}
ofstream myfile;
myfile.open ("12.txt");
myfile << search << "\n";
}
the output in 12.txt is:
2
instead of :
5.66 4.95 2.55 0.99 2.87
0.99 2.87 2.55 4.95 5.66
2.55 0.99 2.87 5.66 4.95

I understand that your are new to C++.
I analyzed your code and put in tons of comments, where the errors are. You need to change your design. Before starting to type in code, you must first write down, what should be done. Then, and this is most important, you think (without taking any language into consideration) how you can solve the problem. This is most important. Also for you later programming career. The design is most important. So think 3 hours, how it could be done. Search possible design solutions in the internet. Write it on a piece of paper or somewhere.
Then, after hours of thinking, select an apropriate language and check, how it could be implemented.
I show a standard C++ solution below. You will not understand it immediately. So please try to understand the design first. Then lookup all used C++-statements in the internet and try to understand.
Read some good C++ books, before starting to code.
Please see first your commented code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std; // You should not use this line at all. Use qualified names.
int main()
{
string line;
double AtomId, Atom_radius, search; // These variables are not initalized
ifstream AtomId_file("r:\\11.txt");
string namefile;
if (AtomId_file.is_open()) { // You should not use is_open but simply if (AtomId_file)
// Here you have a loop running from 0,1,2,3,4,5. That are 6 loops. But you have only 5 lines in your sourcefile
// The you read one line, each time the loops runs. So in the beginning, this will read the first line
for (int linenox = 0; getline(AtomId_file, line) && linenox < 6; linenox++) {
// And only for the first loop event, when linenox==0, you read then next line "2 4.95"
// So you read already lines. But not more.
// ypu need to read line by line (only one per loop) and then store the result in an appropriate STL Container
if (linenox == 0) AtomId_file >> AtomId >> Atom_radius;
}
// Since you assigned the data only once, the values will be 2, 4.95
// They will never change
cout << "AtomId: " << AtomId << " Atom_radius: " << Atom_radius << endl;
// The variable namefile has never been initailized and is always emtpy, So ""
cout << namefile << "\n";
}
ifstream NB("r:\\NB.txt");
size_t pos; // Not initialized
if (NB.is_open()) // Not recommended. Use "if (NB) instead". In general, use more meaningful variable names
{
search = AtomId; // search is now 2 and never somthing else
getline(NB, line); // Read exactly one (and only this one time) a line containing 1, 5.66
pos = line.find(search); // So, 2 will never be found
if (pos != string::npos) // Always false, can never be true
{
search = Atom_radius; // Will never be executed
cout << "Found!"; // Will never be executed
}
}
ofstream myfile; // You can write directly ofstream myfile("12.txt");
myfile.open("12.txt");
myfile << search << "\n"; // And the output will always be 2.
}
And here is a correct and working example:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <iterator>
int main() {
// Open the file 11.txt and check, if it could be opened
if (std::ifstream file11("11.txt"); file11) {
// Define variable id and attribute and initialize them to theire default values.
unsigned int id{};
double attribute{};
// Here we will store all values (id, attribute) of all lines that we read in the follwing loop
std::unordered_map<unsigned, double> replacement{};
// Read in a llop ALL lines and extract id and attribute, and, check if this worked
while (file11 >> id >> attribute) {
// Create a new replacement value for id
replacement[id] = attribute;
}
// So, now, all data from file 11.txt is read and stored.
// We will now read the next file and store the data
// Open next input file NB.txt and check, if that worked
if (std::ifstream fileNB("NB.txt"); fileNB) {
// And already now, open output file 12.txt and check, if open worked
if (std::ofstream myfile("12.txt"); myfile) {
// Read a complete line and check, if that worked. Read all lines in a loop
for (std::string line; std::getline(fileNB, line); ) {
// Put the line in a std::istringstream, so that we can extract each single value
std::istringstream iss(line);
// We will store the single values of the just read line into a vector
// This we do, because we do not know, how many values will be in that line
// We use a so called iterator, to iterate over all elements in the just read line
// The result will be stored in a vector
// The istream_iterator will call the ">>"-operator, until the line is empty
// For the vector, we use its range constructor
std::vector values(std::istream_iterator<unsigned>(iss), {});
// Now go through all values, replace them and out the result into the output file
for (const unsigned& u : values) myfile << replacement[u] << " ";
myfile << "\n";
}
}
}
}
return 0;
}
Of course there are many other possible solutions

Related

Readling a line and using the next lines information c++

I am new to c++ and I need help when reading and changing lines from an input file to use the next lines and saving it into another output file.
I have an example of a single DNA sequence stored in .fastq format, with the following structure.
#Read_1
AGACUUUACGCT
+
++//187-,/02
So each DNA sequence has four lines worth of information.
My goal is to split up the DNA string (line 2, length 12) into different fragments of random length and save each fragment as a separate new sequence. But to keep the .fastq structure I need to keep the information from lines 3 and 4! So the ideal output would be:
#Read_1_1
AGAC
+
++//
#Read_1_2
UU
+
18
#Read_1_3
UACGCT
+
7-,/02
In this ideal output, line 4 from the input has been split to match each DNA fragment (but i can do this with substr, so that's not a problem). My problem is when i am splitting the DNA sequences (line 2) and saving them as a new read, i need the information from line 3 and 4.
I am coding in C++ and i have made some functions which works and made some different attempts which fails:
When I'm opening the file I have made a function (DNA_fragmentation) which randomly splits the DNA (line2) into some fragments, like so:
AGAC
UU
UACGCT
So when I am using this function I am reading line 2, then saving these fragments into a std::vectorstd::string and using a for loop to save these fragments and their read (from line 1) into a new file, giving me the input:
#Read_1_1
AGAC
#Read_1_2
UU
#Read_1_3
UACGCT
My issue is I don't know how to add line 3 and line 4 for each of the new fragments, since they are created when im opening and reading line 2 from the original file. How do i extract information from the next lines?
To read the file and seperate the functions im using this:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
std::string fafq_seq(std::string in_name, std::string out_name) {
std::ifstream myfile(in_name);
std::ofstream out_file(out_name);
if (myfile.is_open() && out_file.is_open())
{
std::string line;
while( std::getline(myfile,line) )
{
int ID = 1;
std::string read_ID;
// This is line 1, which always match with #
if (line.rfind("#",0) == 0) {
continue;
} // Then reading line 2 the DNA sequence
else if (line.rfind("A", 0) == 0 ||
line.rfind("T", 0) == 0 ||
line.rfind("G", 0) == 0 ||
line.rfind("C", 0) == 0){
std::string Seq = line;
// creating a vector with each of the DNA pieces using my DNA_fragmentation function
std::vector<std::string> Damage = DNA_fragmentation(Seq,2,8);
// For each fragment im adding a new read and saving the output
for (int i=0; i<Damage.size();i++){
// adding what corresponds to line 1 starting with #
out_file << "#Read_" << ID << "_" << i+1 << std::endl;
// adding the DNA pieces
out_file << Damage[i] << std::endl;
}
ID += 1;
}
else {
// iterating through line 3 and 4, which is where im not sure how to handle my problem
out_file << line << std::endl;
}
}
out_file.close();
myfile.close();
}
}
int main() {
std::string File = "TestSeq.fastq";
fafq_seq(File,"Test_out.fastq");
return 0;
}
I know its a long question and a bit difficult for me to explain further, but i hope this problem makes sense. But just any comments or help would be appreciated. Thanks.
I think you could make your task much easier overall by reading in the full fastq fragment first, then split it into multiple fragments, and then finally output it all again.
If you make a struct for the fragment and add input and output operators (operator>> and operator<<) for it, then you can do the reading and writing in a very simple way:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct FastqFragment
{
std::string ID;
std::string sequence;
std::string delim;
std::string quality_value;
};
std::istream& operator>>(std::istream& in, FastqFragment& frag)
{
std::getline(in, frag.ID);
if (frag.ID.size() == 0 || frag.ID[0] != '#') {
in.setstate(std::ios_base::failbit);
return in;
}
std::getline(in, frag.sequence);
std::getline(in, frag.delim);
if (frag.delim.size() == 0 || frag.delim[0] != '+') {
in.setstate(std::ios_base::failbit);
return in;
}
std::getline(in, frag.quality_value);
return in;
}
std::ostream& operator<<(std::ostream& out, const FastqFragment& frag)
{
out << frag.ID << '\n';
out << frag.sequence << '\n';
out << frag.delim << '\n';
out << frag.quality_value << '\n';
return out;
}
I tried to add some very basic validation to the read operator, as you can see. Now you can use it something like this:
int main()
{
std::ifstream in("sequence.txt");
std::vector<FastqFragment> frags;
for (FastqFragment tmp; in >> tmp;) {
frags.push_back(tmp);
}
// Insert code for mutating the fragments
for (const auto& f : frags)
std::cout << f;
// or
std::ofstream out("output.txt");
for (const auto& f : frags)
out << f;
}
Now your DNA_fragmentation code can take a FastqFragment struct as argument and split all the strings that needs to be split at the same time.

How to read each number individually from lines when reading from a file

Needing guidance on how to read numbers from a file and setting each individual number from the rows to set up functions
I have read through the file and was able to print out the numbers onto the screen, but I'm running into some understanding on how am I going to be able to print use on of those numbers for a specific function that I am wanting to use. For instance I have
string line;
while(getline(file,line)){
cout<<line<<"\n";
}
/* What the file is and what it prints out onto the screen
3 6
2 3 2
2 1 6
2 1 4
1 2 3
1 1 2
2 1 8
*/
For instance I want to use the 3 and 6 for a function such as
create_list(int x, int y){}
In other words each set set of numbers in each row will be representing input to some functions
Parsing variable number of integers from input line
It is not clear from the question what you are trying to do. As mentioned in the comments, you can parse the file directory using the ifstream. I am lazy and always parse files with getline(<ifstream>, str) and then parse the lines using an istringstream. I make fewer mistakes this way.
One of the questions was why you have multiple line lengths. No matter, I made up functions that were called depending on whether there were 1, 2, or 3 integers for each input line.
The great thing about parsing the input using a stream, is that the stream processor can parse ints, doubles, or whatever.
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
int square(std::vector<int> &ints)
{
return ints[0] * ints[0];
}
int rectangle(std::vector<int> &ints)
{
return ints[0] * ints[1];
}
int volume(std::vector<int> &ints)
{
return ints[0] * ints[1] * ints[2];
}
int main()
{
std::ifstream file;
file.open("example.txt");
std::string str;
while (getline(file, str)) {
int parsed_int;
std::vector<int> ints;
int index = 0;
std::stringstream stream(str);
while (stream >> parsed_int) {
ints.push_back(parsed_int);
++index;
}
int answer = 0;
// index is the number of integers read on this line from the file
switch (index) {
case 0:break;
case 1:answer = square(ints);
break;
case 2:answer = rectangle(ints);
break;
case 3:answer = volume(ints);
break;
default:break;
}
std::cout << "Answer is " << answer << "\n";
}
}

How to keep reading after while loop?

I have a .txt file that has a sequence of numbers and spaces on the first line that I wish to read into a vector. Then there is a '$' symbol on the next line. On the line after that is another line containing a sequence of numbers and spaces (like the first) that I'd like to read into another vector. For example
1 2 3 4 5
$
4 3 2 1 6
I've tried everything but can't keep reading after the initial while loop reads in integers. How do I move past the second line and read the third? Right now It just outputs the first line. Currently, this is my code:
int main(int argc, const char * argv[]) {
ifstream file(argv[1]);
if (file.is_open() && file.good()){
int addMe;
vector<int> addMeList;
while(file>>addMe){
cout <<addMe<<endl;
addMeList.push_back(addMe);
}
string skip;
while(file >> skip)
cout << skip << endl;
int searchQuery;
vector<int> searchQueries;
while(file>>searchQuery){
searchQueries.push_back(searchQuery);
}
for (int i=0; i<searchQueries.size();i++)
{
cout << searchQueries[i]<<endl;
}
}
return 0;
}
Two problems:
The first loop will cause the streams failbit to be set (when it attempts to read the '$' from the second line). If that bit is set, you can't read more from the stream. You need
to clear the stream state.
Once you've done the above, the second loop will read the rest of the file.
One possible solution is to read lines instead. Use e.g. std::getline to read a line. Put the line into a std::istringstream, and read the values from that.
The program logic seems to be flawed. Using the first while loop you read the entire file word-by-word till the very end (not till the end of line), after that trying to read again fails, which is evaluated as false, thus it never even gets into the other loops. Instead, consider reading line by line using getline and then breaking it into ints using istringstream.
Here's how I'd improve it:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream> // include this header to use istringstream
using namespace std;
int main() {
ifstream file("text.txt"); // my test file; Replace with yours
if (file.is_open() && file.good()) {
string lineIn; // general line to read into
int i; // general int to read into
vector<int> addMeList;
// int addMe; // not needed anymore
getline(file, lineIn); // read a line 1
istringstream istr(lineIn); // string stream we can use to read integers from
while (istr >> i) {
cout << i << endl;
addMeList.push_back(i);
}
// string skip; // not needed anymore
getline(file, lineIn); // skips line 2
// int searchQuery; // not needed anymore
vector<int> searchQueries;
getline(file, lineIn); // read a line 2
istringstream istr2(lineIn); // string stream we can use to read integers from
while (istr2 >> i) {
searchQueries.push_back(i);
}
for (int i = 0; i < searchQueries.size(); i++)
{
cout << searchQueries[i] << endl;
}
}
return 0;
}
Input file:
1 2 3 4 5
$
4 3 2 1 6
Output:
1
2
3
4
5
4
3
2
1
6

In C++ why is ifstream getline returning every other number in my .txt file, rather than all of them?

When I run this code it doesn't print the contents of the .txt file which is numbers 1 to 100, it prints all of the even numbers up to 100 (e.g. 2 4 6 8 so on.) And I don't know why, it didn't before and I don't think I changed anything. I'm using xcode. Anybody got any ideas?
#include <stdio.h>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main () {
string line;
int Points[100];
ifstream myfile("StatNum.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
getline(myfile,line);
stringstream(line) >> Points[100]; //uses stringstream to convert Myline (which is a string) into a number and put it into an index of Points
cout << Points[100] << endl;
}
myfile.close();
}
else cout << "Unable to open file" << endl;
return 0;
}
This happens because you call getline twice per iteration:
First, you call it in the while header
Then you call it inside the loop.
One invocation (the one in the while header) is sufficient, because the result is saved in the line variable, which the loop body is free to examine.
Removing the second invocation will fix the problem.
As #dasblinkenlight pointed out, you are calling std::getline() twice and that's the problem that you see.
The problem that you can't see is that you are writing data to Points[100] which is an invalid location, outside of the array's bounds. The 100 valid locations in your array are indexes 0 to 99, that is Points[0], Points[1], ..., Points[99] (because counting in C++ starts from 0, not 1).
Writing to Points[100] is Undefined Behavior which means that your program may crash, or worse: may not crash while corrupting its own data.
Since you're using C++ you have std::vector and other containers at your disposal, where you can easily store the numbers you read:
#include <vector>
// ...
vector<int> points;
while (getline(myfile, line))
{
int temp;
stringstream(line) >> temp;
points.push_back(temp);
cout << temp << endl;
}

Reading only SPECIFIC range of lines in a text file C++

Hi I have a text file which contains some numerical data. Of that text file ONLY the lines
14 to 100 have to be read into my C++ program. Each of these lines contain three numbers corresponding to x,y,z coordinates of a point. Thus, coordinates are given for 87 points in all.
I want to put these numbers into the arrays xp[87] yp[87] and zp[87].
How do I perform this?
Uptil now I have been used to the following
ifstream readin(argv[1])//Name of the text file
for (int i=0; i<=86; ++i)
{
readin>>xp[i]>>yp[i]>>zp[i];
}
But this technique works only for those files which contain 87 lines and the data to be read starts from the first line itself.
In the present case I want to ignore ALL lines before line 14 and ALL lines after line 100
Read line by line, for most flexibility in your format:
#include <fstream>
#include <sstream>
#include <string>
std::ifstream infile("thefile.txt");
std::string line;
unsigned int count = 0;
while (std::getline(infile, line))
{
++count;
if (count > 100) { break; } // done
if (count < 14) { continue; } // too early
std::istringstream iss(line);
if (!(iss >> x[count - 14] >> y[count - 14] >> z[count - 14]))
{
// error
}
}
// all done
In the present case I want to ignore ALL lines before line 14
Since you have to actually read the file to know where a line ends and a new one begins, you will have to then read 13 lines. Use getline() and a dummy string to hold the results from it.
and ALL lines after line 100
Just close the stream and be done with it.
After several years, Range-v3 allows one to write this:
#include <fstream>
#include <iostream>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/getlines.hpp>
#include <range/v3/view/take.hpp>
using namespace ranges;
using namespace ranges::views;
int main() {
std::ifstream ifs{"inputFile"};
auto lines = getlines(ifs) | take(100) | drop(15/* which is 14 - 1 */);
for (auto i : lines) {
std::cout << i << std::endl;
}
}
Requires C++17.