`std::quoted` without using stream? - c++

I'm reading in CSV files and trying to remove the outer quotes. I'm currently using this:
std::string cell = "input "my quoted" cell"; // from `getline()`
std::stringstream cs;
std::string unquoted;
cs << cell;
cs >> std::quoted(unquoted);
This does work, but it seems to me that this is very inefficient, since I have to create a std::stringstream each time. Is there a direct way of removing the quotes (and escaping the inner quotes)?
Thank you in advance!

No it's not possible to quote or unquote with std::quote() without using a stream.
Instead, reuse a stream like the following example. It's fairly efficient.
std::ifstream file_in;
...
for (std::string line; std::getline(file_in, line); ) {
std::istringstream line_in(line);
while (...) { // tokenization loop(parse delimiters)
std::string s;
line_in >> std::quoted(s);
...
}
}

Related

Parsing each line into variables in array

I have this text file and I need to split each field separated by a comma into farray[7] for first-line and Sarray[7] for the second line and so on. Any idea how to do that?
Textfile:
Bill, Gates,10-28-1955,, Microsoft, Windows, 124 Billion
Steve, Jobs,2-24-1955,10-5-2011,Apple, iPad, 10.2 Billion
Linus, Torvalds,12-28-1969,,Linux,, 150 Million
Code :
using namespace std;
int main() {
string line;
int counter=0;
string farray[7],Sarray[7];
ifstream myfile ("projectwinter.txt");
if(myfile.is_open())
{
while(getline(myfile,line,',')){
cout << line <<endl;
}
}
}
First, change your whlie() loop to run to the end of the file and read the whole line first then in your while read the whole string word by word, and whenever and store it in another string variable when a "," comes print the string and then empty the string.
string farray[7];
int farraycount=0;
string str;
while(getline(myfile,str)){
string temp="";
for(int i=0; i<str.length(); i++){
if(str[i]==','){ // may be it can if(str[i]==",") I din't run it on IDE
farray[farraycount++]=temp;
temp="";
}
else
temp=temp+str[i]
}
farray[farraycount++]=temp;
}
So, let us see, how to tackle this problem.
First, we will analyze the requirements, the What
We have comma separated data
The source data is stored in a file
All data shall be read from the file
The data from one line shall be split into parts
All parts belonging to a Person shall be kept together somehow
We want to read as many Person data from the file, as there are available
Next, the How. How could we do that. Please note, there are many possible solutions.
First, we should note that one line of the source file contains structured data with 7 attributes.
In C++ structured data will be stored in structs or classes. So, we will create a struct and name it "Person". It will contain all attributes for a "Person". For example:
struct Person {
std::string name{};
std::string firstName{};
std::string dateOfBirth{};
std::string dateOfDeath{};
std::string company{};
std::string mainProduct{};
std::string assets{};
};
Next, we see that we want to store many Persons somehow. We do not know in advance how many. Similar data will be stored in C++ in so called containers. There are many containers defined in the standard C++ library. Becuase the size of this COnatiner is not fixed from the beginning, it needs to grow dynamically. But else, it should behave like an old C-style array. The best fitting choice is a std::vector. Please look [here][1] for a description.
So, we will define a std::vector<Person> to hold all persons listed in the source file.
Now, as C++ is an object oriented language, we will use objects. Objects hold data and methods, operating on that data in one entity. Objects in c++ are structs or classes. The data we have defined already. Now the methods. The only thing that we want to do, is reading the data from a stream. And for this, we can use iostream facilities. You know the inserter << and extractor >> operators. If, we want to use the same mechanism for our struct, we will add a method, and her specifically an extractor >> operator to our struct.
And because we may need later some output, we will also add an inserter method. This may then look like this:
struct Person {
std::string name{};
std::string firstName{};
std::string dateOfBirth{};
std::string dateOfDeath{};
std::string company{};
std::string mainProduct{};
std::string assets{};
// Overwrite extractor operator
friend std::istream& operator >> (std::istream& is, Person& p) {
// Read all data from stream
std::getline(is, p.name, ',');
std::getline(is, p.firstName, ',');
std::getline(is, p.dateOfBirth, ',');
std::getline(is, p.dateOfDeath, ',');
std::getline(is, p.company, ',');
std::getline(is, p.mainProduct, ',');
std::getline(is, p.assets);
return is;
}
// Overwrite inserter operator
friend std::ostream& operator << (std::ostream& os, const Person& p) {
return os << p.name << ' ' << p.firstName << ' ' << p.dateOfBirth << ' ' << p.dateOfDeath << ' '
<< p.company << ' ' << p.mainProduct << ' ' << p.assets;;
}
};
The struct knows, how many members it has. And it will extract each attribute wit [std::getline][2]. Please note: there are many many possible solutions to split a string into parts. Often you will see a combination of std::getline, std::istringstream and then std::getline working on the std::istringstream.
This would then look like this:
friend std::istream& operator >> (std::istream& is, Person& p) {
if (std::string line{}; std::getline(is, line)) {
std::istringstream iss{ line };
// Read all data from stream
std::getline(iss, p.name, ',');
std::getline(iss, p.firstName, ',');
std::getline(iss, p.dateOfBirth, ',');
std::getline(iss, p.dateOfDeath, ',');
std::getline(iss, p.company, ',');
std::getline(iss, p.mainProduct, ',');
std::getline(iss, p.assets);
}
return is;
}
This is usually the better way. We read always a complete line and then split it. This will reduce problems, if there is an error in one line. Then the rest will continue ok. And, we can exchange the internal splitting mechanism without affecting the outside world.
OK, good, now to main.
We need to open the file. Here we can use the functionality of the std::ifstream. The constructor will open the file for us (and the destructor will close it automatically).
We embed this in an [if][3] statement with initialzer, so that we can check the status of the file in one step.
To read the file we use the range contructor of the std::vector. Please see here, [constructor number 5][4].
As the iterator we use the std::istream_iterator, decribed [here][5]. It will automatically call the extractor of the Person-class until the file is at its end. And will copy the data to the std::vector.
And that's it.
With a one liner, we can do everything.
As mentioned above there are many ways to split a string.
Splitting a string into tokens is a very old task. There are many many solutions available. All have different properties. Some are difficult to understand, some are hard to develop, some are more complex, slower or faster or more flexible or not.
Alternatives
Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
Using old style std::strtok function. Maybe unsafe. Maybe should not be used any longer
std::getline. Most used implementation. But actually a "misuse" and not so flexible
Using dedicated modern function, specifically developed for this purpose, most flexible and good fitting into the STL environment and algortithm landscape. But slower.
Please see 4 examples in one piece of code.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>
using Container = std::vector<std::string>;
std::regex delimiter{ "," };
int main() {
// Some function to print the contents of an STL container
auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };
// Example 1: Handcrafted -------------------------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Search for comma, then take the part and add to the result
for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {
// So, if there is a comma or the end of the string
if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {
// Copy substring
c.push_back(stringToSplit.substr(startpos, i - startpos));
startpos = i + 1;
}
}
print(c);
}
// Example 2: Using very old strtok function ----------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
c.push_back(token);
}
print(c);
}
// Example 3: Very often used std::getline with additional istringstream ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Put string in an std::istringstream
std::istringstream iss{ stringToSplit };
// Extract string parts in simple for loop
for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
;
print(c);
}
// Example 4: Most flexible iterator solution ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
//
// Everything done already with range constructor. No additional code needed.
//
print(c);
// Works also with other containers in the same way
std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
print(c2);
// And works with algorithms
std::deque<std::string> c3{};
std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));
print(c3);
}
return 0;
}
[1]: https://en.cppreference.com/w/cpp/container/vector
[2]: https://en.cppreference.com/w/cpp/string/basic_string/getline
[3]: https://en.cppreference.com/w/cpp/language/if
[4]: https://en.cppreference.com/w/cpp/container/vector/vector
[5]: https://en.cppreference.com/w/cpp/iterator/istream_iterator

Having trouble understanding C++ streams

I have to read some data from an input stream, run it through some filters, and then display the context on screen. I'm working with Windows and currently stuck on this. I'm having a hard time understanding the I/O streams.
I don't know what I should do after passing the data through the first filter because currently, the second function calculates 0 chars?
main:
std::ifstream data("somedata.txt");
whitesprem(data);
calc_chars(data);
whitesprem:
// removes extra white spaces
void whitesprem(std::ifstream& fff) {
std::string line;
while(std::getline(fff, line)){
std::regex rgx("\\s{2,}");
line = std::regex_replace(line, rgx, " ")
//How to move on?
}
}
I'd consume each line inside your whiteprem(). Another approach could be to just copy the data to another string stream from the file stream and use the new stream in the rest of the program.
Probably you intend to do something like this:
void whiteprem(std::ifstream& ff, std::stringstream &update){
std::string line;
while(std::getline(fff, line)){
std::regex rgx("\\s{2,}");
line = std::regex_replace(line, rgx, " ")
//How to move on?
update << line << std::endl;
}
}
int main(){
std::ifstream data("somedata.txt");
std::stringstream ss;
whitesprem(data, ss);
calc_chars(ss);
}

Reading a file into memory C++: Is there a getline() for std::strings

I was asked to update my code that reads in a text file and parses it for specific strings.
Basically instead of opening the text file every time, I want to read the text file into memory and have it for the duration of the object.
I was wondering if there was a similar function to getline() I could use for a std::string like i can for a std::ifstream.
I realize I could just use a while/for loop but I am curious if there is some other way. Here is what I am currently doing:
file.txt: (\n represents a newline )
file.txt
My Code:
ifstream file("/tmp/file.txt");
int argIndex = 0;
std::string arg,line,substring,whatIneed1,whatIneed2;
if(file)
{
while(std::getline(file,line))
{
if(line.find("3421",0) != string::npos)
{
std::getline(file,line);
std::getline(file,line);
std::stringstream ss1(line);
std::getline(file,line);
std::stringstream ss2(line);
while( ss1 >> arg)
{
if( argIndex==0)
{
whatIneed1 = arg;
}
argIndex++;
}
argIndex=0;
while( ss2 >> arg)
{
if( argIndex==0)
{
whatIneed2 = arg;
}
argIndex++;
}
argIndex=0;
}
}
}
Where at the end whatIneed1=="whatIneed1" and whatIneed2=="whatIneed2".
Is there a way to do this with storing file.txt in a std::string instead of a std::ifstream asnd using a function like getline()? I like getline() because it makes getting the next line of the file that much easier.
If you've already read the data into a string, you can use std::stringstream to turn it into a file-like object compatible with getline.
std::stringstream ss;
ss.str(file_contents_str);
std::string line;
while (std::getline(ss, line))
// ...
Rather than grab a line then try to extract one thing from it, why not extract the one thing, then discard the line?
std::string whatIneed1, whatIneed2, ignored;
if(ifstream file("/tmp/file.txt"))
{
for(std::string line; std::getline(file,line);)
{
if(line.find("3421",0) != string::npos)
{
std::getline(file, ignored);
file >> whatIneed1;
std::getline(file, ignored);
file >> whatIneed2;
std::getline(file, ignored);
}
}
}

Using C++ ifstream extraction operator>> to read formatted data from a file

As my learning, I am trying to use c++ ifstream and its operator>> to read data from a text file using code below. The text file outdummy.txt has following contents:
just dummy
Hello ofstream
555
My questions is how to read char data present in the file into a char array or string. How to do this using the ifstream::operator>> in code below.
#include <iostream>
#include <fstream>
int main()
{
int a;
string s;
char buf[100];
ifstream in("outdummy.txt",ios_base::in);
in.operator>>(a); //How to read integer? How to read the string data.??
cout << a;
in.close();
getchar();
return 0;
}
If you want to use formatted input, you have to know in advance what data to expect and read it into variables of the according data type. For example, if you know that the number is always the fifth token, as in your example, you could do this:
std::string s1, s2, s3, s4;
int n;
std::ifstream in("outdummy.txt");
if (in >> s1 >> s2 >> s3 >> s4 >> n)
{
std::cout << "We read the number " << n << std::endl;
}
On the other hand, if you know that the number is always on the third line, by itself:
std::string line;
std::getline(in, line); // have line 1
std::getline(in, line); // have line 2
std::getline(in, line); // have line 3
std::istringstream iss(line);
if (iss >> n)
{
std::cout << "We read the number " << n << std::endl;
}
As you can see, to read a token as a string, you just stream it into a std::string. It's important to remember that the formatted input operator works token by token, and tokens are separated by whitespace (spaces, tabs, newlines). The usual fundamental choice to make is whether you process a file entirely in tokens (first version), or line by line (second version). For line-by-line processing, you use getline first to read one line into a string, and then use a string stream to tokenize the string.
A word about validation: You cannot know whether a formatted extraction will actually succeed, because that depends on the input data. Therefore, you should always check whether an input operation succeeded, and abort parsing if it doesn't, because in case of a failure your variables won't contain the correct data, but you have no way of knowing that later. So always say it like this:
if (in >> v) { /* ... */ } // v is some suitable variable
else { /* could not read into v */ }
if (std::getline(in, line)) { /* process line */ }
else { /* error, no line! */ }
The latter construction is usually used in a while loop, to read an entire file line by line:
while (std::getline(in, line)) { /* process line */ }
ifstream has ios_base::in by default. You don't need to specify it.
operator>> can be invoked directly as an operator: in >> a.
Reading strings is the same: in >> s, but the caveat is that it is whitespace-delimited, so it will read "just" by itself, without "dummy".
If you want to read complete lines, use std::getline(in, s).
Since you have elected to use C-strings, you can use the getline method of your ifstream object (not std::getline() which works with std::strings), which will allow you to specify the C-string and a maximum size for the buffer.
Based on what you had, and adding an additional buffer for the second line:
char buf[100];
char buf2[100];
in.getline(buf,sizeof(buf));
in.getline(buf2,sizeof(buf2));
in >> a;
However, as the other poster has proposed, try using the std::string and its methods, it will make your life easier.
You can read file contents and use a Finite State Machine for parsing.
Example:
void Parse(const char* buffer, size_t length);
size_t GetBufferSize();
size_t bufferSize = GetBufferSize();
char* buffer = new char[bufferSize];
std::ifstream in("input.txt");
while(in.getline(buffer, bufferSize)) {
Parse(buffer, in.gcount());
}
Alternatively, you can use a tool like Flex to write your parser.

While reading a file (ifstream), is there any way to direct it to make a new line?

While reading a file (ifstream), is there any way to direct it to make a new line?
For instance, I would like for THIS to happen:
myfile>>array[1]>>array[2]>>endl;
Obviously, the "endl" just isn't allowed. Is there another way to do this?
Edit---thanks for the quick responses guys!
From a text file, I'm trying to store two strings from that file into arrays and then do the same with the next line (or until I desire, using a for loop)
Using strings is important to me as it will make my future program a lot more flexible.
Several options:
You can use ignore.
myfile >> array[1] >> array[2];
myfile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Or you can read each line into as string stream
std::string line;
std::getline(myfile,line);
std::stringstream stream(line);
stream >> array[1] >> array[2];
Please note: Array indexing starts at 0.
Use std::getline to read a line into a memory stream, then get the two strings from that.
while (cin)
{
string line;
getline(cin, line);
stringstream stream;
stream << line;
stream >> array[1]>>array[2];
}
Read your two items, then call myfile.ignore(8192, '\n')
I have no idea what this question means. Here's a simple way to read all the lines of a file into a vector of strings. It might be easier to do what you want to do if you do this first.
std::vector<std::string> lines;
std::string line;
while (std::getline(myFile, line))
lines.push_back(line);
Now you can say lines[4] to get the fifth line, or lines.size() to find out how many lines there were.
This should work:
stringstream stream;
string sLine;
int iLine;
while (cin)
{
getline(cin, sLine);
stream << sLine;
stream >> data[iLine][0] >> data[iLine][1];
}
Customized version of an earlier answer.