Extract and set variables from input file c++ - c++

So I want to get a specific part from every line of the input file.
So far I got this:
ifstream fin("text.txt");
string line;
while (getline(fin, line)) {
if (line.find("Set") == 0)
{
istringstream sin1(line.substr(line.find("path1=") + 1));
sin1 >> path1;
istringstream sin2(line.substr(line.find("path2=") + 1));
sin2 >> path2;
}
}
From what I understood the (line.substr(line.find("VAR_CAL_PATH2=") + 1)) part will take whatever it's after "path1=" and will put it into path1, I guess I got it wrong. My input file has two lines:
Set path1="somepath"
Set path2="someotherpath"
When the while loop ends I get path1="Set" and path2="someotherpath" but what I want is path1="somepath" and path2="someotherpath"

As #Jordfräs says, find() returns the position of the start of the string.
When you try to parse the path2 value, you overwrite the value of path1.
The code with these fixes:
const string path1field = "path1=";
const string path2field = "path2=";
string path1 = "", path2 = "";
ifstream fin("text.txt");
string line;
while (getline(fin, line))
{
if (line.find("Set") != string::npos)
{
size_t path1pos = line.find(path1field);
size_t path2pos = line.find(path2field);
if (path1pos != string::npos)
{
istringstream sin1(line.substr(path1pos + path1field.length()));
sin1 >> path1;
}
if (path2pos != string::npos)
{
istringstream sin2(line.substr(path2pos + path2field.length()));
sin2 >> path2;
}
}
}
cout << "path1: " << path1 << endl;
cout << "path2: " << path2 << endl;

The find() function in std::string returns the position of the start of the string. Adding 1 will point to the start + 1, not the position after the string you search for.
There is plenty of good documentation of the standard library available, e.g., http://en.cppreference.com/w/cpp/string/basic_string/find

Another (more general) solution for string variables could be:
ifstream fin("text.txt");
string line;
const vector<string> pathsNames={"path1=", "path2="};
vector<string> paths(pathsNames.size());
while (getline(fin, line)) {
if (line.find("Set") == 0)
{
for(std::vector<string>::size_type x=0; x<pathsNames.size(); x++){
if(line.find(pathsNames[x])!=string::npos){
paths[x]=line.substr(line.find(pathsNames[x]) + pathsNames[x].length());
break;
}
}
}
}
//print results
for(std::vector<string>::size_type x=0; x<pathsNames.size(); x++){
cout << pathsNames[x] << paths[x] << endl;
}

Related

How to add spaces into a text file?

I have a text file like this:
100,Nguyen Van A,2004
101,Tran Thi B,2004
102,Vo Van C,2005
103,Truong Thi D,2005
How can I add one blank space right after each "," into that file using C++?
I've tried using find() function but nothing worked.
svFile.open("list_student.txt");
while (getline(svFile, line, ','))
{
if (line.find(",", 0) != string::npos)
svFile << " ";
}
Two options, read and write the file character by character, or option 2, read the entire text file into a string and then perform your required changes and write the file back:
Option 1 (Character by Character):
char ch;
fstream fin("list_student.txt", fstream::in);
fstream fout("list_student_result.txt", fstream::out);
while (fin >> noskipws >> ch) {
fout << ch;
if (ch==',')
{
fout << ' ';
}
}
fout.close();
Option 2 (Read/Write entire file):
#include <iostream>
#include <fstream>
int main()
{
// Read the entire file
std::ifstream t("list_student.txt");
std::stringstream buffer;
buffer << t.rdbuf();
std::string myString = buffer.str();
size_t start = 0;
int pos = 0;
// Set your start character and replace with string here
std::string comma(",");
std::string replaceWith(", ");
// Replace the comma "," with ", " (and a space)
while ((pos = myString.find(comma, pos)) != std::string::npos) {
myString.replace(pos, comma.length(), replaceWith);
pos += replaceWith.length();
}
// Write the formatted text back to a file
std::ofstream out("list_student_result.txt");
out << myString;
out.close();
return 0;
}

How to separate data from getline each time there is a space

int main() {
ifstream billFile;
billFile.open("bill.in"); //opening file
if( billFile.is_open() ){
string line1;
getline(billFile, line1);
cout << line1 << endl;
}
The bill.in file contains:
12 100
How can I separate 12 and 100 into two different variables?
You can use std::istringstream to parse line1:
int main()
{
ifstream billFile("bill.in"); //opening file
if( billFile.is_open() )
{
string line1;
if( getline(billFile, line1) )
{
istringstream iss(line1);
int value1, value2;
if( iss >> value1 >> value2 )
cout << value1 << ' ' << value2 << endl;
}
}
}
Of course, if your file has only 1 line, then you can just omit getline(), eg:
int main()
{
ifstream billFile("bill.in"); //opening file
if( billFile.is_open() )
{
int value1, value2;
if( billFile >> value1 >> value2 )
cout << value1 << ' ' << value2 << endl;
}
}
I use the following split function to divvy up each line based on some set of delimiters (a space in your case).
std::vector<std::string> split(const std::string& str,
std::string delims = " \t") {
std::vector<std::string> strings;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delims, end)) != std::string::npos) {
end = str.find_first_of(delims, start);
strings.push_back(str.substr(start, end - start));
}
return strings;
}
then you can split each line into a vector of strings:
int main() {
ifstream billFile;
billFile.open("bill.in"); //opening file
if( billFile.is_open() ){
string line;
getline(billFile, line);
std::vector<std::string> str = split(line, " ");
std::string line1 = str[0];
cout << line1 << endl;
}
}
You use this method to split up strings using any delimiter you want.
If you input file only contains one line and your keyboard is in very poor working order and you really need to minimize keystrokes you can write:
int main(){
int v1, v2;
if(std::ifstream("bill.in") >> v1 >> v2){
// here you have valid v1 and v2.
}
}
The >> "formatted input" is appropriate here because it is convenient to understand the contents of the text file as numbers.
Function std::getline() takes delimitation as claimed in C++ reference. So just use getline(istream, str, ' ');.
Modify your codes as
int main() {
ifstream billFile;
billFile.open("bill.in"); //opening file
if( billFile.is_open() ){
string line1;
getline(billFile, line1, ' ');
cout << line1 << endl;
}

How to skip blank lines when reading a file in c++?

Ok, so here is the text of the file I am trying to read:
KEYS
a set of keys
3
LAMP
a brightly shining brass lamp
8
ROD
a black rod with a rusty star
12
Ok, so pretend that each line is evenly spaced, but there are 2 blank lines, (or tabs) between 8 and ROD. How would I skip that and continue with the program? I am trying to put each line into 3 vectors (so keys, lamp, and rod into one vector etc). Here is my code (but it does not skip the blank line).:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
using namespace std;
int main() {
ifstream objFile;
string inputName;
string outputName;
string header;
cout << "Enter image file name: ";
cin >> inputName;
objFile.open(inputName);
string name;
vector<string> name2;
string description;
vector<string> description2;
string initialLocation;
vector<string> initialLocation2;
string line;
if(objFile) {
while(!objFile.eof()){
getline(objFile, line);
name = line;
name2.push_back(name);
getline(objFile, line);
description = line;
description2.push_back(description);
getline(objFile, line);
initialLocation = line;
initialLocation2.push_back(initialLocation);
} else {
cout << "not working" << endl;
}
for (std::vector<string>::const_iterator i = name2.begin(); i != name2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = description2.begin(); i != description2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = initialLocation2.begin(); i != initialLocation2.end(); ++i)
std::cout << *i << ' ';
I think you can check to see if the string is empty thru std::getline. If it is, then you can ignore it or something like.
getline(objFile, line);
name = line;
while(name.length() == 0)
{
getline(objFile, line);
name = line;
}
name = line;
name2.push_back(name);
getline(objFile, line);
description= line;
while(description.length() == 0)
{
getline(objFile, line);
description = line;
}
description= line;
description2.push_back(description);
getline(objFile, line);
initialLocation = line;
while(initialLocation.length() == 0)
{
getline(objFile, line);
initialLocation = line;
}
initialLocation = line;
initialLocation2.push_back(initialLocation );
If i am correct then a line will have no length if it is blank and if it is we check again therefore ignoring it.
You can use std::getline() (As pointed out by many people) instead... which will yield each line one-by-one:
inline std::string ReadFile(std::ifstream& stream)
{
std::string contents;
std::string temporary;
while (std::getline(stream, temporary))
if (!std::all_of(temporary.begin(), temporary.end(), isspace))
contents.append(temporary + "\n");
return contents.substr(0, contents.size() - 1);
}
And yes, an example:
int main()
{
std::ifstream is("file.txt");
if (is.fail())
return 1;
auto const contents = ReadFile(is);
is.close();
std::cout << contents << std::endl;
std::cin.get();
return 0;
}

Read and parse specific parts of the file

I have an input file with the following content:
Tstart: 13:51:45
Tend: 13:58:00
and I'd like to have the timestamps in separate strings at the end. So far, I've written the following:
// open the info file
if (infile.is_open())
{
// read the info regarding the played video
string line;
while (getline(infile, line))
{
istringstream iss(line);
string token;
while (iss >> token)
{
string tStart = token.substr(0, 6);
string tEnd = token.substr(7,2);
cout << tStart << tEnd<< endl;
}
}
infile.close();
}
else
cout << "Video info file cannot be opened. Check the path." << endl;
and I get the following output:
Tstart
13:51:5
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr: __pos (which is 7) > this->size() (which is 5)
I do understand what the error says, but I cannot find another way of doing this in C++.
Anyone has an idea?
String line will be one line of text. First it will be "Tstart: 13:51:45", and in the next iteration it will be "Tend: 13:58:00".
String token will be part of the line that is delimited with space. So, if line is "Tstart: 13:51:45" then token will be "Tstart:" in first iteration and "13:51:45" in second iteration. This is not what you need.
Instead of the inner while loop I suggest searching for a space with string::find and then taking everything after the space with string::substr:
bool is_first_line = true;
string tStart, tEnd;
while (getline(infile, line))
{
int space_index = line.find(' ');
if (space_index != string::npos)
{
if (is_first_line)
tStart = line.substr(space_index + 1);
else
tEnd = line.substr(space_index + 1);
}
is_first_line = false;
}
cout << tStart << tEnd << endl;
If it is not known in advance which line has which value then we can still get away from inner loop:
string tStart, tEnd;
while (getline(infile, line))
{
int space_index = line.find(' ');
if (space_index != string::npos)
{
string property_name = line.substr(0, space_index);
if (property_name == "Tstart:")
tStart = line.substr(space_index + 1);
else if (property_name == "Tend:")
tEnd = line.substr(space_index + 1);
}
}
cout << tStart << tEnd << endl;

C++ Tokenize part of a String

Trying to tokenize a String in C++ which is read from a file, separated by commas, but I only need the first 3 data of every line.
For example:
The lines look like this:
140,152,2240,1,0,3:0:0:0:
156,72,2691,1,0,1:0:0:0:
356,72,3593,1,0,1:0:0:0:
But I only need the first 3 data of these lines. In this case:
140, 152, 2240156, 72, 2691356, 72, 3593
I'm trying to add these data into a vector I just don't know how to skip reading a line from the file after the first 3 data.
This is my current code: (canPrint is true by default)
ifstream ifs;
ifs.open("E:\\sample.txt");
if (!ifs)
cout << "Error reading file\n";
else
cout << "File loaded\n";
int numlines = 0;
int counter = 0;
string tmp;
while (getline(ifs, tmp))
{
//getline(ifs, tmp); // Saves the line in tmp.
if (canPrint)
{
//getline(ifs, tmp);
numlines++;
// cout << tmp << endl; // Prints our tmp.
vector<string> strings;
vector<customdata> datalist;
istringstream f(tmp);
string s;
while (getline(f, s, ',')) {
cout << s << " ";
strings.push_back(s);
}
cout << "\n";
}
How about checking the size of the vector first? Perhaps something like
while (strings.size() < 3 && getline(f, s, ',')) { ... }