c++ get multiple lines - c++

I need a way to read the lines a user has pasted in the console. The user pastes it in this fashion:
1st line: n - number of lines except this one
2nd - nth: a string object
If I read it with cin, it reads the first line, exits the program, and the next lines is placed in the console input. With scanf I get similar results.
string s[100];
int N = 0;
scanf("%i", N);
for (int i = 0; i < N; i++)
{
scanf("%s", s);
}

It would be better if you used a std::vector<std::string> and use std::getline to extract the lines:
std::vector<std::string> lines;
std::string line;
while (std::getline(std::cin >> std::ws, line))
{
if (!line.empty())
lines.push_back(line);
}

getline() will do the trick for you. Try this:
string lines[100];
int number = 0;
cin >> number;
for (int idx = 0; idx != number; ++idx)
{
getline(cin, lines[idx]);
}
Note that you cannot read more than 100 lines this way. If you want to dynamically allocate an array of lines of size n, you can use the new operator.

Related

Properly handling input when file has less numbers than expected

I'm attempting to read in a file with 3 floating point numbers per line. Right now, I have this implemented as:
std::ifstream inFile(inName.c_str());
if (!inFile) {
prterr("in ASCII file could not be opened!\n");
return -1;
}
std::vector<double> xData, yData, zData;
xData.resize(nPoints);
yData.resize(nPoints);
zData.resize(nPoints);
inFile.precision(std::numeric_limits<double>::digits10+1);
for (int i = 0; i < nPoints; ++i) {
inFile >> xData[i] >> yData[i] >> zData[i];
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
so that the program successfully runs even if the user inputs more than 3 numbers per line. However, sometimes a user tries to run the program with <3 numbers per line. When this happens, the parser will obviously store the data incorrectly.
I would like to either (a) throw an error if the file has less than 3 numbers per line, or (b) Only store the first N numbers per line in their respective vectors if only N numbers per line are present in the file. The trick is, I want to do this as quickly as possible, as my datasets can be several GBs. I can be guaranteed that my file has the exact same amount of numbers per line.
Is there a graceful and efficient way to perform (b)? I know I could implement (a) just by reading the first line as a string separately before the for loop, but that seems quite ugly. Is there a better way to do this?
I know you dd not want to read in the first line as a std::string but you need someway to find out how many white space separated columns there are and unfortunately a newline is treated like white space. If you are okay with doing that though then you can see how man columns you have with
std::ifstream inFile(inName.c_str());
std::vector<int> columns_in_file;
std::string temp;
std::getline(inFile, temp);
std::stringstream ss(temp);
int number;
while (ss >> number)
columns_in_file.push_back(number);
Then what we need to do is set up a 2d vector that will have the correct number of columns and rows.
// get number of columns. 3 max
int columns = columns_in_file.size() <= 3 ? columns_in_file.size() : 3;
std::vector<std::vector<int>> data(nPoints, std::vector<int>(columns));
// now we add the data we already read
for (int i = 0; i < columns; i++)
data[0][i] = columns_in_file[i];
Now we have a vector that is the same size as the file unless the file has more then 3 columns and has the first line of data in it. Now we have a decision to make, since you will only ever need to call
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
while reading if columns_in_file.size() > 3, then we don't want to call it if it is not needed. We could either have the reading code in two different functions or in two different blocks in an else if statement. The latter is what I will show but know you could refactor it into function calls. So to actually read the file we would have something like
if (columns <= 3)
{
for (int i = 0; i < nPoints; i++)
{
for(int j = 0; j < columns; j++)
{
infile >> data[i][j];
}
}
}
else
{
for (int i = 0; i < nPoints; i++)
{
for(int j = 0; j < columns; j++)
{
infile >> data[i][j];
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
}
You can first get the number of columns in the file while reading the first set of values,as a string, and then use the count with another loop inside the first for loop:
[EDIT] As per the comments given(and the learning continues again), instead of making the all vectors resize initially, you can resize them depending on the available columns. this will avoid unnecessary space consumption for the unused vectors.
std::vector<double> Data[3];//the x,y,z data set(Assuming the maximum number of columns can't be >3)
//you can decide which of the vectors(x,y,z) are used by looking at the column count
inFile.precision(std::numeric_limits<double>::digits10+1);
int count=0;//count the number of columns
string first_line;
double temp;
getline(inFile,first_line);
istringstream ss(first_line);
while(ss>>temp && count<3)
{
Data[count].resize(nPoints);
Data[count][0]=temp;
count++;
}
for(int i=1; i<nPoints&& inFile.peek() != EOF ; i++)
{
for(int j=0;j<count;j++)
{
inFile>>temp;
Data[j][i]=temp;
}
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Reading list of integers into an Array C++

I am working on a program in C++ that will read integers from a file, then pass them to a function that checks for a Subset Sum.
The file is formatted like so:
number of cases n
sum for case 1
list of integers separated by a space
sum for case
list of integers separated by a space
sum for case n
list of integers separated by a space
My problem now lies in how to read the list of integers into an array to be passed to my function.
This is my main so far:
fstream infile("subset.txt");
if(infile.is_open()){
int numCases, num;
infile >> numCases;
while(infile >> num){
for(int i = 0; i < numCases; i++)
{
int sum;
int set[30];
num >> sum;
for(int i = 0; i < 30; i++)
{
if(num == '\n')
{
sum[i] = -1
}
else
{
num << sum[i]
}
}
int n = sizeof(set)/sizeof(set[0]);
if(subsetSum(set, n, sum) == true)
printf("True");
else
printf("False");
}
}
}
else
printf("File did not open correctly.");
return 0;
Any help you guys can give me would be greatly appreciated.
Yes, this is for an assignment, so if you would rather just give me hints that would be appreciated as well. The assignment is for the algorithm and I have that working, I just need a hand with the I/O.
I would read the line containing the list of numbers using std::getline, then use an istringstream to parse numbers out of that string.
I'd also use a std::vector instead of an array to hold the numbers. For the actual parsing, I'd probably use a pair of std::istream_iterators, so the code would look something like this:
while (infile >> sum) {
std::getline(infile, line);
std::istringstream buffer(line);
std::vector<int> numbers{std::istream_iterator<int>(buffer),
std::istream_iterator<int>()};
std::cout << std::boolalpha << subsetSum(numbers, sum);
}

How can I transfer a text file to array 2D in C++?

How can i transfer a text file(.txt) to array 2D in c++ and this is my source code
fstream fin('textfile.txt', ios::in);
int matrix[n][m]; // n is the number of rows and m is the number of columns
for(int i = 0;i < n; i++){
for(int j = 0; j<m; j++){
fin>>matrix[i][j];
}
}
but how can i detemine n and m for do this,i need your help and your advice, please Join us your perspectives
This solution requires C++11+
If there is no n & m in the file, you must assume that the layout is also in 2D
One Two Three
Four Five Six
Warning:: Untested code.
std::stringstream res;
std::string wordUp;
std::vector<std::string> str;
// the matrix, vector of vector of strings.
std::vector<std::vector<std::string>> matrix;
fstream fin('textfile.txt', ios::in);
int lines = 0;
int words = 0;
// read the file line by line using `getline`
for (std::string line; std::getline(fin, line); ) {
++lines;
// use stringstream to count the number of words (m).
res.str(line); // assign line to res. might also need some reset of good().
while (res.good()) {
res >> wordUp;
str.push_back(wordUp);
++words;
}
matrix.push_back(str);
str.erase(str.begin());
}
So u mean u want to read a file and copy contents to char Matrix[][]??, you can use while loop to read characters, and split every 1024 bytes(1 kb) by lines, i mean do this:
#include <fstream.h>
int main()
{
int n=0, m=0, MAX_LINES=1025, i=0, j=0;
char character, Matrix[1024][1025];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
for (i=0; i<1025; i++)
{
for (j=0; j<=1024 || Matrix[i][j]!='\0'; j++)
cout<<Matrix[i][j];
}
return 0;
}
This code will read 1024×1024 chars, but if the txt file is less than 1024(m) characters, the while loop will be exited and Matrix[n][m]='\0'; statement is executed.
EDIT: As asked by David i have written the whole code with main() sorry bro i forget, the bug in the code was the variables n and m were intialised to 1025 and 1024 so the program skips writing to Matrix as the Matrix[1024][1025] cannot store more characters... I think this would help, ok bro...

Data parsing from text file

i have encountered an issue regarding parsing values from a text file. What i am trying to do is i need to add up all the values for each specific events for all days and find the average of it. Example will be (290+370+346+325+325)/5 and (5+5+5+12)/4 based on the data in the text file.
A sample is listed below
For each line --> First event:Second event:Third event...:Total number of event:
Every new line is considered a new day.
3:290:61:148:2:5:
2:370:50:173:4:5:
5:346:87:131:4:
3:325:60:145:5:5:
3:325:60:145:5:12:13:7:
I have tried to do it myself but i have only managed to store each column in a string array only. Sample code below. Will appreciate if you guys can help, thanks!
void IDS::parseBase() {
string temp = "";
int counting = 0;
int maxEvent = 0;
int noOfLines = 0;
vector<string> baseVector;
ifstream readBaseFile("Base-Data.txt");
ifstream readBaseFileAgain("Base-Data.txt");
while (getline(readBaseFile, temp)) {
baseVector.push_back(temp);
}
readBaseFile.close();
//Fine the no. of lines
noOfLines = baseVector.size();
//Find the no. of events
for (int i=0; i<baseVector.size(); i++)
{
counting = count(baseVector[i].begin(), baseVector[i].end(), ':') - 1;
if (maxEvent < counting)
{
maxEvent = counting;
}
}
//Store individual events into array
string a[maxEvent];
while (getline(readBaseFileAgain, temp)) {
stringstream streamTemp(temp);
for (int i=0; i<maxEvent; i++)
{
getline(streamTemp, temp, ':');
a[i] += temp + "\n";
}
}
}
I suggest:
int a[maxEvent];
char c; // to hold the colon
while(streamTemp >> a[i++] >> c);

C++ parse, fetch a variable number of integers from a string

I have a set of strings which looks like
"4 7 14 0 2 blablabla"
"3 8 1 40 blablablablabla"
...
The first number N correspond to how many numbers will follow.
Basically, the format of a string is N+1 numbers, separated with a space, followed by an unknown number of irrelevant characters at the end that I don't need.
How can I get all the numbers in variables or a dynamic structure given that I don't know the number N in advance ?
In other words, I'd like something like:
sscanf(s, "%d %d %d %d",&n,&x,&y,&z);
which would work no matter how many numbers in the string.
The first thing would be to break up the input into lines, by using
getline to read it. This will greatly facilitate error recovery and
resynchronization in case of error. It will also facilitate parsing;
it's the strategy which should be adopted almost every time a newline in
the input is significant. After that, you use a std::istringstream to
parse the line. Something like:
std::vector<std::vector<int> > data;
std::string line;
while ( std::getline( input, line ) ) {
std::istringstream l( line );
int iCount;
l >> iCount;
if ( !l || iCount < 0 ) {
// format error: line doesn't start with an int.
} else {
std::vector<int> lineData;
int value;
while ( lineData.size() != iCount && l >> value ) {
lineData.push_back( value ) ;
}
if ( lineData.size() == iCount ) {
data.push_back( lineData );
} else {
// format error: line didn't contain the correct
// number of ints
}
}
}
int input;
std::vector<int> ints;
while(std::cin >> input) //read as long as there is integer
ints.push_back(input);
std::cin.clear(); //clear the error flag
//read the remaining input which most certainly is non-integer
std::string s = "3 54 -4 42 fdsvadsdsberwte";
std::istringstream source(s);
std::vector<int> ints;
int num = 0;
int temp = 0;
if (source >> num) // read the first number and if it succeeds, read the rest
{
while(source >> temp) ints.push_back(temp);
// Here, I'd compare the size of the vector with what was
// expected (num) and act accordingly.
}
else
{
// format error
}
You could do it something like this:
std::string buffer;
while(std::getline(in, buffer)) { // read a line
std::istringstream str(buffer); // put line in a stringstream for parsing
int count;
str >> count; // read first number
std::vector<int> numbers(count); // reserve space for other numbers
for(int i = 0; i < count; i++) { // read other numbers
str >> numbers[i];
}
}
Initialize an istringstream with your string, and read from it:
std::istringstream ss(s);
int N;
ss >> N;
std::vector<int> a(N); //int* a = new int[N];
for (int i=0;i<N;i++)
ss >> a[i];
You can use dynamic array and a linked list, of dynamic array type. After reading a line initialize the array using number N and insert the numbers sequentially on each index. Insert the node containing line data to linked list.
Pseudo code:
int *lineNumbers;
lineNumbers = new int[N];
List<int*> data;
data.insert(lineNumbers);