I am building a function extract the last names from an array and print the name to screen. I have been able to extract the first last name in the array but then the output concatenates the first index's first name with the following index positions last name. Below is my code, thanks for the help!
{
stringstream ss;
string name;
for(int i=0; i < elements; i++)
{
ss << first[i];
ss >> name;
int pos = name.find(",");
cout << pos;
string last = name.substr(0,pos);
cout << "\"" << last << "\"" << endl;
}
cout << endl;
}
It is because the way you are using string streams.
Every time you read a new name from the array, you're adding it to the output buffer. You then read the next word from the buffer so therefore, you never skip the first name . For what it looks like you're doing, you can just eliminate the string stream all together and just stick to the standard input and output (cin/cout). Otherwise, clear the buffer everytime you read in a new string (ss.clear());
for(int i = 0; i < elements.size(); i++){
int pos = elements[i].find(",");
cout << "\"" << elements[i].substr(0,pos) << "\"" << endl;
}
Try the following code:
int main()
{
string name = "asd,kkaa";
int pos = name.find(",");
if(string::npos != pos)
{
string part1 = name.substr(0,pos);
string part2 = name.substr(pos+1);
cout << "\"" << part1 << "\"" << endl;
cout << "\"" << part2 << "\"" << endl;
}
return 0;
}
// output:
// "asd"
// "kkaa"
I think it's OK, so could give us more your input value?
Related
I have been struggling with comparing two strings which I read from files, "one" & "two" both have the same words (e.g. salt) but it doesn't return "Equal". I have also used == but it made no difference.
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
int main (){
string en[100];
string line;
int i=0;
ifstream fileEn ("hey.txt");
if (fileEn.is_open()){
while (!fileEn.eof()){
getline(fileEn,line);
en[i]=line;
i++;
}
}
fileEn.close();
string fa[100];
string line1;
i=0;
ifstream fileFa ("hey1.txt");
if (fileFa.is_open()){
while (!fileFa.eof()){
getline(fileFa,line1);
fa[i]=line1;
i++;
}
}
fileFa.close();
ifstream Matn("matn.txt");
string matn[100];
if(Matn.is_open()){
for(int i = 0; i < 100; ++i){
Matn >> matn[i];
}
}
Matn.close();
string one = en[0];
string two = matn[0];
cout << one << " " << two;
if(one.compare(two) == 0){
cout << "Equal";
}
}
I suggest adding some debugging output to your program:
while (!fileEn.eof()){
getline(fileEn,line);
// Debugging output
std::cout << "en[" << i << "] = '" << line << "'" << std::endl;
en[i]=line;
i++;
}
and
for(int i = 0; i < 100; ++i){
Matn >> matn[i];
// Debugging output
std::cout << "matn[" << i << "] = '" << matn[i] << "'" << std::endl;
}
Hopefully you can see what the problem is by looking at the output.
In addition, please note that use of while (!fileEn.eof()){ ... } is not correct. See Why is iostream::eof inside a loop condition considered wrong?.
I suggest changing that loop to:
while (getline(fileEn,line)) {
// Debugging output
std::cout << "en[" << i << "] = '" << line << "'" << std::endl;
en[i]=line;
i++;
}
Similarly, don't assume that Matn >> matn[i] is successful. I suggest changing that loop to:
for(int i = 0; i < 100; ++i) {
std::string s;
if ( !(Matn >> s) )
{
// Read was not successful. Stop the loop.
break;
}
matn[i] = s;
// Debugging output
std::cout << "matn[" << i << "] = '" << matn[i] << "'" << std::endl;
}
So in this program I'm trying to go through word by word and make it only lowercase letters, no whitespace or anything else. However, my string "temp" isn't holding anything in it. Is it because of the way I'm trying to modify it? Maybe I should try using a char * instead? Sorry if this is a stupid question, I'm brand new to c++, but I've been trying to debug it for hours and can't find much searching for this.
#include <string>
#include <iostream>
#include <fstream>
#include <ctype.h>
using namespace std;
int main(int argc, char* argv[]) {
/*if (argc != 3) {
cout << "Error: wrong number of arguments." << endl;
}*/
ifstream infile(argv[1]);
//infile.open(argv[1]);
string content((std::istreambuf_iterator<char>(infile)),
(std::istreambuf_iterator<char>()));
string final;
string temp;
string distinct[5000];
int distinctnum[5000] = { 0 };
int numdist = 0;
int wordcount = 0;
int i = 0;
int j = 0;
int k = 0;
int isdistinct = 0;
int len = content.length();
//cout << "test 1" << endl;
cout << "length of string: " << len << endl;
cout << "content entered: " << content << endl;
while (i < len) {
temp.clear();
//cout << "test 2" << endl;
if (isalpha(content[i])) {
//cout << "test 3" << endl;
if (isupper(content[i])) {
//cout << "test 4" << endl;
temp[j] = tolower(content[i]);
++j;
}
else {
//cout << "test 5" << endl;
temp[j] = content[i];
++j;
}
}
else {
cout << temp << endl;
//cout << "test 6" << endl;
++wordcount;
final = final + temp;
j = 0;
for (k = 0;k < numdist;k++) {
//cout << "test 7" << endl;
if (distinct[k] == temp) {
++distinctnum[k];
isdistinct = 1;
break;
}
}
if (isdistinct == 0) {
//cout << "test 8" << endl;
distinct[numdist] = temp;
++numdist;
}
}
//cout << temp << endl;
++i;
}
cout << wordcount+1 << " words total." << endl << numdist << " distinct words." << endl;
cout << "New output: " << final << endl;
return 0;
}
You can't add to a string with operator[]. You can only modify what's already there. Since temp is created empty and routinely cleared, using [] is undefined. The string length is zero, so any indexing is out of bounds. There may be nothing there at all. Even if the program manages to survive this abuse, the string length is likely to still be zero, and operations on the string will result in nothing happening.
In keeping with what OP currently has, I see two easy options:
Treat the string the same way you would a std::vector and push_back
temp.push_back(tolower(content[i]));
or
Build up a std::stringstream
stream << tolower(content[i])
and convert the result into a string when finished
string temp = stream.str();
Either approach eliminates the need for a j counter as strings know how long they are.
However, OP can pull and endrun around this whole problem and use std::transform
std::transform(content.begin(), content.end(), content.begin(), ::tolower);
to convert the whole string in one shot and then concentrate on splitting the lower case string with substring. The colons in front of ::tolower are there to prevent confusion with other tolowers since proper namespacing of the standard library has been switched off with using namespace std;
Off topic, it looks like OP is performing a frequency count on words. Look into std::map<string, int> distinct;. You can reduce the gathering and comparison testing to
distinct[temp]++;
I am trying to load a text file and import the contents into a vector of structs.
Here are my definitions
typedef struct
{
string pcName, pcUsername, pcPassword, pcMessage, pcAdvertisement; //I know that
//this is incorrect convention. It was originally a char*
}
ENTRY;
vector<ENTRY> entries;
fstream data;
Here is my display data function
void DisplayData()
{
std::cout << (int)(entries.size() / 5) <<" entries" << endl;
for(int i = 1; i <=(int)entries.size()/5; i++)
{
cout << endl << "Entry " << i << ":" << endl
<< "Name: " << entries[i].pcName << endl
<< "Username: " << entries[i].pcUsername << endl
<< "Password: " << entries[i].pcPassword << endl
<< "Message: " << entries[i].pcMessage << endl
<< "Advertisement: " << entries[i].pcAdvertisement << endl;
}
}
and here is my Load Data function
bool LoadData(const char* filepath)
{
std::string lineData ;
int linenumber = 1 ;
data.open(filepath, ios::in);
ENTRY entry_temp;
if(!data.is_open())
{
cerr << "Error loading file" << endl;
return false;
}
while(getline(data, lineData))
{
if(linenumber==1) {entry_temp.pcName = lineData;}
else if(linenumber==2) {entry_temp.pcUsername = lineData;}
else if(linenumber==3) {entry_temp.pcPassword = lineData;}
else if(linenumber==4) {entry_temp.pcMessage = lineData;}
else if(linenumber==5) {entry_temp.pcAdvertisement = lineData;}
entries.push_back(entry_temp);
if(linenumber == 5)
{
linenumber = 0;
}
linenumber++;
}
data.close();
puts("Database Loaded");
return true;
}
Here is the text file I am loading:
Name1
Username1
Password1
Message1
Ad1
And here is the result of the display data function after calling load data:
1 entries
Entry 1:
Name: Name1
Username Username1
Password:
Message:
Advertisement:
As you can see, the first two load but the last three don't. When I did this with an array instead of a vector, it worked fine so I don't know what I'm doing wrong. Thanks.
I suggest that you read each line directly into the data field where it goes:
getline(data, entry_temp.pcName);
getline(data, entry_temp.pcUsername);
getline(data, entry_temp.pcPassword);
getline(data, entry_temp.pcMessage);
getline(data, entry_temp.pcAdvertisement);
entries.push_back(entry_temp);
This makes your intent much clearer than your current while loop. It also creates a single entry for all 4 input lines rather than one for each input line (with the other three blank). Now you can read several "entries" by using a while loop that checks if you have reached the end of the file.
Doing this will also make printing out the data much easier since the vector will have exactly the number of entries rather than five times as many as you expect (which also eats up a lot more memory than you need to).
Your DisplayData function is a little weird, and so is your LoadData.
Your LoadData pushes back a new copy of the current ENTRIES entry with every line. Your DisplayData starts at 1 (which is not the beginning of any vector or array), and iterates only up to the 1/5th entry of the entire vector.
This needs a heavy rework.
First, the size() member of any standard container returns the number of elements that it contains, and will not take the number of fields in a contained struct into account.
For future reference, you'll want to post your question in a complete, standalone example that we can immediately compile to help. (see http://sscce.org/)
Try this modified data, which runs correctly, and see if you can tell what is being done differently:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
typedef struct
{
string pcName, pcUsername, pcPassword, pcMessage, pcAdvertisement;
}
ENTRY;
vector<ENTRY> entries;
fstream data;
bool LoadData(const char* filepath)
{
std::string lineData ;
int linenumber = 1 ;
data.open(filepath, ios::in);
ENTRY entry_temp;
if(!data.is_open())
{
cerr << "Error loading file" << endl;
return false;
}
while(getline(data, lineData))
{
if(linenumber==1) {entry_temp.pcName = lineData;}
else if(linenumber==2) {entry_temp.pcUsername = lineData;}
else if(linenumber==3) {entry_temp.pcPassword = lineData;}
else if(linenumber==4) {entry_temp.pcMessage = lineData;}
else if(linenumber==5) {entry_temp.pcAdvertisement = lineData;}
if(linenumber == 5)
{
entries.push_back(entry_temp);
linenumber = 0;
}
linenumber++;
}
data.close();
puts("Database Loaded");
return true;
}
void DisplayData()
{
std::cout << entries.size() <<" entries" << endl;
for(int i = 0; i < entries.size(); i++)
{
cout << endl << "Entry " << i << ":" << endl
<< "Name: " << entries[i].pcName << endl
<< "Username: " << entries[i].pcUsername << endl
<< "Password: " << entries[i].pcPassword << endl
<< "Message: " << entries[i].pcMessage << endl
<< "Advertisement: " << entries[i].pcAdvertisement << endl;
}
}
int main()
{
LoadData("/tmp/testdata");
DisplayData();
return (0);
}
While I think #code-guru has the right idea, I'd take the same idea just a little further, and make your code work a little more closely with the standard library. I'd do that by reading a data item with a stream extractor, and displaying it with stream inserter. So, the extractor would look something like this:
std::istream &operator>>(std::istream &is, ENTRY &e) {
getline(is, e.pcName);
getline(is, e.pcUsername);
getline(is, e.pcPassword);
getline(is, e.pcMessage);
getline(is, e.pcAdvertisement);
return is;
}
..and the inserter would look something like this:
std::ostream &operator<<(std::ostream &os, ENTRY const &e) {
os << e.pcName << "\n";
os << e.pcUsername << "\n";
os << e.pcPassword << "\n";
os << e.pcMessage << "\n";
os << e.pcAdvertisement << "\n";
return os;
}
With those in place, loading and displaying the data becomes fairly straightforward.
Load the data:
std::ifstream in("yourfile.txt");
std::vector<ENTRY> data((std::istream_iterator<ENTRY>(in)),
std::istream_iterator<ENTRY>());
Display the data:
for (auto const & e: data)
std::cout << e << "\n";
For the moment, I haven't tried to duplicate the format you were using to display the data -- presumably the modifications for that should be fairly obvious.
I've been having trouble with reading text files in c++, particularly when assigning a line to a variable.
I have the following code:
ifstream fx;
fx.open(nomeFich);
if(!fx)
{cout << "FX. nao existe!" <<endl;}
string linha="";;
int pos, inic;
while(!fx.eof())
{
getline(fx,linha);
if(linha.size() > 0)
{
cout << linha << endl;
inic=0;
pos=0;
pos=linha.find(",",inic);
cout << pos << endl;
string nomeL1(linha.substr(inic,pos));
cout << "atribuiu 1" << endl;
inic=pos;
cout <<"inic: " << inic << " pos:" << pos <<endl;
pos=linha.find(',',inic);
string nomeL2(linha.substr(inic,pos));
cout << "atribuiu 2" << endl;
inic=pos;
cout <<"inic: " << inic << " pos:" << pos <<endl;
pos=linha.find(',',inic);
cout << "atribuiu 3" << endl;
string dist(linha.substr(inic,pos));
When it does the cout << linha << endl; it returns something like :
= = == = = = = == = = = = = = = == = = = = == = = = = =
I've googled it quite a lot and can't find an answer.
I'm new to C++ so don't bash too much xD
Don't do this:
while(!fx.eof())
{
getline(fx,linha); // Here you have to check if getline() actually succeded
// before you do any further processing.
// You could add if (!fx) { break;}
// STUFF;
}
But the better design is:
while(getline(fx,linha)) // If the read works then enter the loop otherwise don't
{
// STUFF
}
You are failing to move past the comma:
inic=pos; // pos is the position of the last ',' or std::string::npos
pos=linha.find(',',inic); // So here pos will be the same as last time.
// As you start searching from a position that has a comma.
ifstream has a getline function, it accepts a char* as the first parameter and the maximum length as the second.
ifstream also has operator>> which you should be using for input, but it will read till whitespace, which is not what you want.
::getline that you're using should also work, but that's assuming that the stream is OK, which as mentioned before, you don't check correctly. You should be checking for errors after calling it, because if you reach EOF or there's an error, you won't know until the whole loop is done.
Also, what's in the file? Maybe what you're getting is the correct result?
# include <iostream>
# include <ctime>
using namespace std;
int stripWhite(char *str);
int main ()
{
char str[50];
cout << "Enter a sentence . " << endl;
cin >>str;
cout << "Your sentence without spaces is : " << endl;
cout << (str) << endl; // This is my problem. The sentence only prints the first word
stripWhite(str);
cout << "There were " << stripWhite(str) << " spaces." << endl;
return 0;
}
int stripWhite(char *str)
{
char *p = str;
int count = 0;
while (*p)
{
if (*p != ' ')
count++;
{
*p++;
}
}
return count;
If you don't want to replace your function with the C++ string type, you can use cin.getline to get a c string (char array)
cin.getline(str, 50);
std::cin treats spaces as end of string indicators.
In order to get the full sentence use std::getline. since this expects a std::string as one of its parameters, you will have to adjust your stripWhite-function accordingly:
# include <iostream>
# include <string>
using namespace std;
int stripWhite(string str); //change the formal parameter's type
int main ()
{
string str;
cout << "Enter a sentence . " << endl;
getline(cin, str,'\n'); //use getline to read everything that has been entered till the press of enter
cout << "Your sentence without spaces is : " << endl;
cout << (str) << endl; // This is my problem. The sentence only prints the first word
stripWhite(str);
cout << "There were " << stripWhite(str) << " spaces." << endl;
system("pause");
return 0;
}
int stripWhite(string str)
{
int count = 0;
char* p = str.c_str;
while (*p)
{
if (*p != ' ')
count++;
{
*p++;
}
}
return count;
}
As pointed out by others, you should use std::getline instead of cin >> str.
However, there are multiple other problems in the code you provided.
Why use char array when you could use std::string ? Why are you so sure that 50 characters will be enough ?
Your stripWhite function doesn't seem to strip anything : you count the number of non-space characters, but you are not actually removing anything. Note that if you switch to std::string instead of plain of char arrays, you could use a standard algorithm to do the job (on the top of my head, I guess std::remove would be appropriate)
Assuming that stripWhite did actually modify the input string, why would you want to call it twice from your main ? If the goal is to strip the string in the first place, and then print the number of removed space, make stripWhite return the number of removed spaces and store this result in the main.
For example :
const int nbSpacesStripped = stripWhite(str);
cout << "There were " << nbSpacesStripped << "spaces." << endl;
Behold Boost String Algorithms and more particularly the replace/erase routines.
# include <iostream>
# include <string>
size_t stripWhiteSpaces(std::string& str)
{
size_t const originalSize = str.size();
boost::erase_all(str, ' ');
return originalSize - str.size();
}
int main ()
{
std::string str;
std::cout << "Enter a sentence . \n";
getline(std::cin, str);
size_t const removed = stripWhiteSpaces(str);
std::cout << "Your sentence without spaces is :\n";
std::cout << (str) << '\n';
std::cout << "There were " << removed << " spaces.\n";
system("pause");
}