Let's say I have a file of names such as:
"erica","bosley","bob","david","janice"
That is, quotes around each name, each name separated by a comma with no space in between.
I want to read these into an array of strings, but can't seem to find the ignore/get/getline/whatever combo to work. I imagine this is a common problem but I'm trying to get better at file I/O and don't know much yet. Here's a basic version that just reads in the entire file as one string (NOT what I want, obviously):
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
fstream iFile("names.txt", ios::in);
string names[5];
int index = 0;
while(iFile)
{
iFile >> names[index];
index++;
}
for(int i = 0; i < 5; i++)
{
cout << "names[" << i << "]: " << names[i] << endl;
}
Output:
names[0]: "erica","bosley","bob","david","janice"
names[1]:
names[2]:
names[3]:
names[4]:
Also, I understand why it all gets read as a single string, but then why are the remaining elements not filled with garbage?
To be clear, I want the output to look like:
names[0]: erica
names[1]: bosley
names[2]: bob
names[3]: david
names[4]: janice
The easiest way to handle this:
Read the entire file and place it into a string, Here is an example of how to do it.
Split the string that you got from number 1. Here is an example of how to do that.
Stream extraction delimits by a space. Therefore the entire file gets read as one string. What you want instead is to split the string by commas.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <sstream>
fstream iFile("names.txt", ios::in);
string file;
iFile >> file;
std::istringstream ss(file);
std::string token;
std::vector<std::string> names;
while(std::getline(ss, token, ',')) {
names.push_back(token);
}
To remove the quotes, use this code:
for (unsigned int i = 0; i < names.size(); i++) {
auto it = std::remove_if(names[i].begin(), names[i].end(), [&] (char c) { return c == '"'; });
names[i] = std::string(names[i].begin(), it);
}
remove_if returns the end iterator for the transformed string, which is why you construct the new string with (s.begin(), it).
Then output it:
for (unsigned int i = 0; i < names.size(); i++) {
std::cout << "names["<<i<<"]: " << names[i] << std::endl;
}
Live Example
Related
I'm trying to read in a text file that is 200 x 1000 of numbers into an array. Each number is separated by a tab. I thought using a 2D array would be good for this situation since it would allow me to distinguish between the individual rows. Being able to distinguish between the individual rows is important in this situation which is why I wanted to do it in this manner. Right now I have the following:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream file("text.txt");
if(file.is_open())
{
string myArray[1000];
for(int i = 0; i < 1000; ++i)
{
file >> myArray[i];
cout << myArray[i] << endl;
}
}
}
Which currently scans the first row of numbers into the array and then prints it out. I wanted to have a 2D array that scans each individual row into the array but keeps them separate. This means the content of row 1 is separate from the content of row 2. I figured a 2D array would do this. I am a bit stuck on this part. I attempted to make a 2D array through the use of a nested for loop but when I tried to copy the values over into the array things started to go wrong. The order was incorrect and the rows were not separated. I am coding this in C++. If someone could help me understand how to import a text document like the one I described and send all that information to a 2D array I would greatly appreciate it. Thanks.
You can use a stringstream to extract the numbers from each row. Also, you don't need to have an array of strings. You can just use one string.
int main()
{
ifstream file("text.txt");
if(file.is_open())
{
for(int i = 0; i < 1000; ++i)
{
string row;
if ( std::getline(file, row) )
{
std::istringstream istr(row);
int number;
while ( istr >> number )
{
// Add the number to a container.
// Or print it to stdout.
cout << number << "\t";
}
cout << endl;
}
}
}
}
If your dimensions change, you use the following code. Note that you can use std::copy to copy from a std::stringstream into a std::vector:
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
int main()
{
std::string input =
"11 12\n"
"21 22\n"
"31 32\n"
"41 42\n"
;
std::stringstream file(input);
std::string temp;
while (std::getline(file, temp)) {
std::stringstream line(temp);
std::vector<std::string> v;
std::copy(
std::istream_iterator<std::string>(line),
std::istream_iterator<std::string>(),
std::back_inserter(v));
for (auto x: v)
std::cout << x << " ";
std::cout << "\n";
}
}
I'm trying to convert a sentence from upper case to lowercase. I also write a code but I stopper when a space is appear. How can I fix this problem and convert the whole sentence? Here is my code
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char str[100];
cin>>str;
for(int i=0;i<strlen(str);i++)
{
if(str[i]>='A'&&str[i]<='Z')
{
str[i]=str[i]+32;
}
}
cout<<str<<endl;
return 0;
}
It's because of theinput operator >>, it breaks on space. If you want to read a whole line then use std::getline to read into a std::string instead.
Then read about the C++ standard algorithms, like for example std::transform. Also, std::tolower doesn't modify anything that's not an upper-case letter, so it's a good function to use.
The error is because operator>> delimites on spaces. The alternative is to use getline. See the following example:
#include <cstring>
#include <iostream>
#include <string>
int main() {
std::string s;
std::getline(std::cin, s);
std::cout << "Original string: " << s << std::endl;
if (!std::cin.fail()) {
const int len = strlen(s.c_str());
for (size_t i = 0; len > i; ++i) {
if ((s[i] >= 'A') && (s[i] <= 'Z'))
s[i] = s[i] - 'A' + 'a';
}
}
std::cout << "New string: " << s << std::endl;
return 0;
}
The reason input stops at whitespace is because formatted input is delimited by whitespace characters (among others). You will need unformatted I/O in order to extract the entire string into str. One way to do this is to use std::istream::getline:
std::cin.getline(str, 100, '\n');
It's also useful to check if the input succeeded by using gcount:
if (std::cin.getline(str, 100, '\n') && std::cin.gcount())
{
...
}
But in practice it's recommended that you use the standard string object std::string which holds a dynamic buffer. To extract the entire input you use std::getline:
std::string str;
if (std::getline(std::cin, str)
{
...
}
Here is one of the examples of doing it using transform function.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str;
if (getline(cin, str))
{
transform(str.begin(), str.end(), str.begin(), ptr_fun<int, int>(toupper));
}
cout << str << endl;
return 0;
}
I have a class called StringList consisting of a constructor and a de-structor. What I am shooting for is for the ability of my program to retain its strings in the array even after it is not running. The way i want to do this is to have my constructor function read strings from a file and store them into my string array (str[]). My de-structor will save my current strings into my file. I am having trouble reading and storing from the file when memory is created. I want each word to be one element in the array.
For example, in the file that is being read from, the strings are stored as such:
HELLO
MOM
DAD
FOUR
YELLOW
I want each word to be a slot. In other words. str[0] = HELLO, str[1]= MOM, str[2]=DAD and such.
Here is my constructor function:
StringList::StringList()
{
numberOfStrings=0;
str = new string[1000000];
ifstream myfile ("Read.txt");
if (myfile.is_open())
{
for (int i = 0; i < 1000000; i++)
{
getline(myfile,str[i]);
numberOfString++;
}
myfile.close();
}
}
Problem here is the for (int i=0; i<100000;i++) line
What this did is continue to fill each blank space into the element until it reached 100000.
Same if i put i<20, it would read all the contents and add blanks to fill to 20. Is there anyway to fill up to the amount of actual strings in the txt. file?
NumberOfStrings++ is outside of your for loop when you read (i.e. it only gets incremented once). Also please consider using std::vector<std::string> instead of a dynamic array.
Here's a version of your code using std::vector instead of an array:
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
class StringList
{
public:
StringList(): str(1000000), numberOfStrings(0)
{
std::ifstream myfile ("Read.txt");
if (myfile.is_open())
{
for (int i = 0; i < str.size(); i++)
{
getline(myfile, str[i]);
numberOfStrings++;
}
myfile.close();
}
}
StringList::~StringList()
{
std::ofstream os("Read.txt");
for (int i = 0; i <numberOfStrings; i++)
{
os << str[i] << std::endl;
}
}
private:
std::vector<std::string> str;
int numberOfStrings;
};
As you can see the changes are rather minimal.
The numberOfStrings variable is only updated once after the for loop has finished. You can also simplify this without the need to specify a large number of lines to read by checking the return value of getline for failure. If you try to read past the end of file is getline will return false.
numberOfStrings = 0;
str = new std::string[1000000];
std::ifstream myfile("Read.txt");
if (myfile.is_open())
{
std::string line;
while(getline(myfile, str[numberOfStrings]))
numberOfStrings++;
myfile.close();
}
You can simplify this even further by using std::vector. To expand on the example provided in your answer StringList might look something like below.
StringList.h
#include <vector>
#include <string>
class StringList
{
public:
StringList();
void PrintWords();
private:
size_t numberOfLines;
std::vector<std::string> str;
};
StringList.cpp to read in single line into each string
#include "StringList.h"
#include <fstream>
StringList::StringList()
{
std::ifstream myfile("Read.txt");
if (myfile.is_open())
{
std::string line;
while(getline(myfile, line))
{
lines_.push_back(line);
}
myfile.close();
}
numberOfLines = str.size();
}
StringList.cpp to read in single word into each string using std::istream_itertor and std::copy
#include "StringList.h"
#include <fstream>
#include <istream>
#include <algorithm> // std::copy
#include <iterator> // istream_iterator
StringList::StringList()
{
std::ifstream myfile("Read.txt");
if (myfile.is_open())
{
std::copy(
istream_iterator<string>(myfile),
istream_iterator<string>(),
back_inserter(str));
}
numberOfLines = str.size();
}
Some other function to print the words
StringList::PrintWords()
{
for(size_t i = 0; i < numberOfLines; ++i)
{
std::cout << str[i] << std::endl;
}
}
I also recommend avoiding using using namespace std in your code. It pulls everything from std into the current scope (typically the global namespace) and can cause conflicts with identifiers.
This would be my approach to reading the data (this doesn't quite work the same as the other answers, but as long as your wordlist doesn't contain words with whitespace, it should work fine).
#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::fstream myFile("read.txt");
if (myFile.is_open())
{
std::istream_iterator<std::string> iter(myFile), end;
std::vector<std::string> str(iter, end);
// print contents
for (int i = 0; i < str.size(); i++)
std::cout << i << ": " << str[i] << std::endl;
}
}
References:
istream_iterator
vector
You can continue to averse std::vector all you want, but for a scenario like this, it is the best tool for the job.
I need to read in a text file of 500 words or more(a real world article from newspaper, etc..) and locate and tag like this, <location> word <location/>, and then print the entire article on the screen. Im using boost regex right now and its working ok. I want to try and use a list or array or some other data structure to have a list of the states and major cities, and search those and compare to the aticle. right now I'm using an array but I'm willing to use anything. Any ideas or clues?
#include <boost/regex.hpp>
#include <iostream>
#include <string>
#include <boost/iostreams/filter/regex.hpp>
#include <fstream>
using namespace std;
int main()
{
string cities[389];
string states [60];
string filename, line,city,state;
ifstream file,cityfile, statefile;
int i=0;
int j=0;
cityfile.open("c:\\cities.txt");
while (!cityfile.eof())
{
getline(cityfile,city);
cities[i]=city;
i++;
//for (int i=0;i<500;i++)
//file>>cities[i];
}
cityfile.close();
statefile.open("c:\\states.txt");
while (!statefile.eof())
{
getline(statefile,state);
states[j]=state;
//for (int i=0;i<500;i++)
//cout<<states[j];
j++;
}
statefile.close();
//4cout<<cities[4];
cout<<"Please enter the path and file name "<<endl;
cin>>filename;
file.open(filename);
while (!file.eof())
{
while(getline(file, line)
{
}
while(getline(file, line))
{
//string text = "Hello world";
boost::regex re("[A-Z/]\.[A-Z\]\.|[A-Z/].*[:space:][A-Z/]|C........a");
//boost::regex re(
string fmt = "<locations>$&<locations\>";
if(boost::regex_search(line, re))
{
string result = boost::regex_replace(line, re, fmt);
cout << result << endl;
}
/*else
{
cout << "Found Nothing" << endl;
}*/
}
}
file.close();
cin.get(),cin.get();
return 0;
}
If you are after asymptotic complexity - Aho-Corasick algorithm offers a linear time complexity ( O(n+m)) (n and m are the lengths of the input strings). for searching a dictionary in a string.
An alternative is to put the tokenized words in a map (where the value is a list to the places in the stream of each string), and search for each string in the data in the tree. The complexity will be O(|S| * (nlogn + mlogn) ) (m being the number of searched words, n is the number of words in the string, and |S| is the length of the average word)
You can use any container that has a .find() method or supports std::find(). I'd use set, since set::find() runs in less than linear time.
Here is a program which does what you talk about. Note that the parsing doesn't work great, but that's not what I'm trying to demonstrate. You could continue to find the words using your parser, and use the call to set::find() to determine if they are locations.
#include <set>
#include <string>
#include <iostream>
#include <sstream>
const std::set<std::string> locations { "Springfield", "Illinois", "Pennsylvania" };
int main () {
std::string line;
while(std::getline(std::cin, line)) {
std::istringstream iss(line);
std::string word;
while(iss >> word) {
if(locations.find(word) == locations.end())
std::cout << word << " ";
else
std::cout << "<location>" << word << "</location> ";
}
std::cout << "\n";
}
}
I'm trying to read from a file, and make a vector of all the words from the file. What I tried to do below is have the user input the filename, and then have the code open the file, and skip characters if they aren't alphanumeric, then input that to a file.
Right now it just closes immediately when I input the filename. Any idea what I could be doing wrong?
#include <vector>
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
string line; //for storing words
vector<string> words; //unspecified size vector
string whichbook;
cout << "Welcome to the book analysis program. Please input the filename of the book you would like to analyze: ";
cin >> whichbook;
cout << endl;
ifstream bookread;
//could be issue
//ofstream bookoutput("results.txt");
bookread.open(whichbook.c_str());
//assert(!bookread.fail());
if(bookread.is_open()){
while(bookread.good()){
getline(bookread, line);
cout << line;
while(isalnum(bookread)){
words.push_back(bookread);
}
}
}
cout << words[];
}
I think I'd do the job a bit differently. Since you want to ignore all but alphanumeric characters, I'd start by defining a locale that treats all other characters as white space:
struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['0'], &rc['9']+1, std::ctype_base::digit);
std::fill(&rc['a'], &rc['z']+1, std::ctype_base::lower);
std::fill(&rc['A'], &rc['Z']+1, std::ctype_base::upper);
return &rc[0];
}
};
That makes reading words/numbers from the stream quite trivial. For example:
int main() {
char const test[] = "This is a bunch=of-words and 2#numbers#4(with)stuff to\tseparate,them, I think.";
std::istringstream infile(test);
infile.imbue(std::locale(std::locale(), new digits_only));
std::copy(std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
For the moment, I've copied the words/numbers to standard output, but copying to a vector just means giving a different iterator to std::copy. For real use, we'd undoubtedly want to get the data from an std::ifstream as well, but (again) it's just a matter of supplying the correct iterator. Just open the file, imbue it with the locale, and read your words/numbers. All the punctuation, etc., will be ignored automatically.
The following would read every line, skip non-alpha numeric characters and add each line as an item to the output vector. You can adapt it so it outputs words instead of lines. I did not want to provide the entire solution, as this looks a bit like a homework problem.
#include <vector>
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string line; //for storing words
vector<string> words; //unspecified size vector
string whichbook;
cout << "Welcome to the book analysis program. Please input the filename of the book you would like to analyze: ";
cin >> whichbook;
cout << endl;
ifstream bookread;
//could be issue
//ofstream bookoutput("results.txt");
bookread.open(whichbook.c_str());
//assert(!bookread.fail());
if(bookread.is_open()){
while(!(bookread.eof())){
line = "";
getline(bookread, line);
string lineToAdd = "";
for(int i = 0 ; i < line.size(); ++i)
{
if(isalnum(line[i]) || line[i] == ' ')
{
if(line[i] == ' ')
lineToAdd.append(" ");
else
{ // just add the newly read character to the string 'lineToAdd'
stringstream ss;
string s;
ss << line[i];
ss >> s;
lineToAdd.append(s);
}
}
}
words.push_back(lineToAdd);
}
}
for(int i = 0 ; i < words.size(); ++i)
cout << words[i] + " ";
return 0;
}