I would like some advice/help in regards to splitting up a paragraph from a separate text file into their own strings. The code I have so far just counts the total amount of words in that paragraph but I would like to split it so each line is 1 sentence then count how many words are in that sentence/line then put that into its' own array so I can do other things with that specific sentience/line. Here is what I have code wise:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
std::ifstream inFile;
inFile.open("Rhymes.txt", std::ios::in);
if (inFile.is_open())
{
string word;
unsigned long wordCount = 0;
while (!inFile.eo())
{
inFile >> word;
if (word.length() > 0)
{
wordCount++;
}
}
cout << "The file had " << wordCount << " word(s) in it." << endl;
}
system("PAUSE");
return 0;
}
The separate text file is called "Rhymes.txt" and that contains:
Today you are You, that is truer than true. There is no one alive who is Youer than You.
The more that you read, the more things you will know. The more that you learn, the more places you'll go.
How did it get so late so soon? Its night before its afternoon.
Today was good. Today was fun. Tomorrow is another one.
And will you succeed? Yes indeed, yes indeed! Ninety-eight and three-quarters percent guaranteed!
Think left and think right and think low and think high. Oh, the things you can think up if only you try!
Unless someone like you cares a whole awful lot, nothing is going to get better. It's not.
I'm sorry to say so but, sadly it's true that bang-ups and hang-ups can happen to you.
So the first line would be its own sentence and when the code is executed it would say:
The line has 19 words in it
I am a bit confused as too how I would go about doing this. I have seen examples of splitting sentences into words but I couldn't find anything that I could really understand that had to do with what I am asking for.
Under the assumption that each white space is exactly one blank character, and there is no plenking/klemping, you can count via std::count. Reading in the lines can be done via std::getline.
int main()
{
// Simulating the file:
std::istringstream inFile(
R"(Today you are You, that is truer than true. There is no one alive who is Youer than You.
The more that you read, the more things you will know. The more that you learn, the more places you'll go.
How did it get so late so soon? Its night before its afternoon.
Today was good. Today was fun. Tomorrow is another one.
And will you succeed? Yes indeed, yes indeed! Ninety-eight and three-quarters percent guaranteed!
Think left and think right and think low and think high. Oh, the things you can think up if only you try!
Unless someone like you cares a whole awful lot, nothing is going to get better. It's not.
I'm sorry to say so but, sadly it's true that bang-ups and hang-ups can happen to you.)");
std::vector<std::string> lines; // This vector will contain all lines.
for (std::string str; std::getline(inFile, str, '\n');)
{
std::cout << "The line has "<< std::count(str.begin(), str.end(), ' ')+1 <<" words in it\n";
lines.push_back(std::move(str)); // Avoid the copy.
}
for (auto const& s : lines)
std::cout << s << '\n';
}
If you need the amount of words in each sentence later on, save an std::pair<std::string, std::size_t> to save both the line and the word count - alter the loop body to this:
std::size_t count = std::count(str.begin(), str.end(), ' ') + 1;
std::cout << "The line has "<<count<<" words in it\n";
lines.emplace_back(std::move(str), count);
I'd write something like:
vector<string> read_line()
{ string line, w;
vector<string> words;
getline(cin, line);
stringstream ss(line);
while(ss >> w)
words.push_back(w);
return words;
}
The returned vector contains the information you need: count of words and the words themselves (with punctuation which you can remove easily).
vector<string> words = read_line();
cout << "This line has " << words.size() << " words in it" << endl;
To read all lines you do:
while(1)
{ vector<string> words = read_line();
if(words.size() == 0) break;
// process line
}
Related
I am currently trying to write a text based RPG. I am working on the user input and how they will choose their actions. I am attempting to take each word from a sentence that the user inputs and put them each separately into an array. That way it can analyze each word and know what the user is attempting to do. I cannot seem to figure out how to go about doing that. I have been looking all around the internet but no one seems to have the same problem as I do. Theres nothing wrong with my code I just cant seem to figure out how.
Here is an example:
#include<iostream>
#include<string>
int main () {
string input [arrayLength];
int arrayLength;
std::cout<<"You are in a mysterious place and you see a creepy man. You don't know where you are. What do you do?"<< std::endl;
//In this case you could either type "run" , "ask man location" , "fight man".
}
I want the user to be able to type any of these commands at any time and then set the variable arrayLength to how many words there are, and then put each word into the array.
How would I do this?
You can use std::istringstream to easily extract the individual words from the input string.
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
int main()
{
std::cout << "You are in a mysterious place and you see a creepy man.\n";
std::cout << "You don't know where you are. What do you do?" << std::endl;
// Get input from the user
std::string line;
std::getline(std::cin, line);
// Extract the words
std::istringstream input(line);
std::string word;
std::vector<std::string> words;
while (input >> word)
words.push_back(word);
// Show them just for fun
for (auto&& word : words)
std::cout << word << '\n';
}
This will wait for the user to enter a complete line before processing it. This is important since std::cin by default treats newline characters as whitespaces during stream operations and will skip them.
While reading in data from a separate text file, it doesn't keep the spaces and instead looks comes out looking like :
Todayyouareyouerthanyou,thatistruerthantrue
When it should have the spaces and say:
Today you are youer than you, that is truer than true
Here is my code that I have so far:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
std::ifstream inFile;
inFile.open("Rhymes.txt", std::ios::in);
if (inFile.is_open())
{
string word;
unsigned long wordCount = 0;
while (!inFile.eo())
{
cout << word;
inFile >> word;
if (word.length() > 0)
{
wordCount++;
}
}
cout << "The file had " << wordCount << " word(s) in it." << endl;
}
system("PAUSE");
return 0;
}
The "Rhymes.txt" has many phrases such as the one above and I'll just add 2 more so it's not a lot on here. Here they are:
Today you are You, that is truer than true. There is no one alive who is Youer than You.
The more that you read, the more things you will know. The more that you learn, the more places you'll go.
How did it get so late so soon? Its night before its afternoon.
Any help or advice would be greatly appreciated!! Also I am a beginner so if this turns out to be something really obvious, sorry!
How about inserting the spaces back to your output, so instead of this
cout << word;
You put this:
cout << word << " ";
Another option would be to read whole lines from your input file and then split them to words.
Issues that I see:
You are writing out word before the first read.
Reading the words using inFile >> word skips the white spaces. You need to add code to write the white spaces.
I am not sure what you were thinking with the following block of code. But, it is not necessary.
if (word.length() > 0)
{
wordCount++;
}
You can simplify your while loop to:
while (inFile >> word)
{
cout << word << " ";
wordCount++;
}
This will print an extra white space at the end. If that is objectionable, you can add more logic to fix that.
Let's fix the typo: inFile.eo() -> inFile.eof() and include stdlib.h for system(). Now you can put the spaces back by writing cout << word << " ";
But your program seems to be out by 1. Linux wc says 53 words but your program says 54. So I fixed your loop like this:
while (true)
{
inFile >> word;
if (inFile.eof())
break;
if (word.length() > 0)
{
wordCount++;
cout << word << " ";
}
}
Now it agrees with wc.
Our professor gave us this assignment, where we have a .txt file with the following format:
John 23
Mary 56
Kyle 99
Gary 100
...etc. etc.
What we have to do is read the file, and store the names and scores in parallel arrays.
This is turning out to be a bit more challenging to me than I anticipated. What is confusing me, when searching around stack, is all the different libraries people use to do this. Our Prof just wants us to use string, fstream, and sstream to do this.
Below is what I've come up with so far, it compiles perfectly, splits the scores from the names but stores them in the same array:
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
const int SIZE = 50;
string names[SIZE];
int score [SIZE];
short loop = 0;
string line;
ifstream inFile("winners.txt");
if (inFile.is_open())
{
while(!inFile.eof())
{
istream& getline(inFile >> line);
names[loop] = line;
cout << names[loop] << endl;
loop++;
}
inFile.close();
}
else cout << "Can't open the file" << endl;
return 0;
}
I'm not looking for someone to solve my HW problem, I just want a push in the right direction!
If you want to read two things for each line of input, it seems reasonable to have two "read" statements:
std::string name;
inFile >> name;
int score;
inFile >> score;
std::cout << "Read score " << score << " for name " << name << '\n';
...then you can do that repeatedly until you've read the entire file.
Edit: After you get the basic logic worked out, you might want to think about error handling. For example, what is appropriate behavior for your program if the input file doesn't contain 50 pairs of (name, score)? How can you change your code to get that behavior?
Each line in the file consists of a name and a score separated by whitespace. You're reading each line but not splitting it into its parts (the name and the score).
Ideally you would use a vector for this, but since it seems that you were asked to use arrays we'll stick with arrays. What you have above looks good until you start reading entries. A more idiomatic way to accomplish this is to use std::getline, i.e.
ifstream inFile( "winners.txt" );
std::string line;
while( std::getline( inFile, line )) {
// Do work here.
}
Inside the loop you need to split the line on the space. Without solving the problem for you, I suggest you take a look at the find and substr functions of the string class: here. They will give you everything you need to solve the problem.
I used this function but it is wrong.
for (int i=0; i<sen.length(); i++) {
if (sen.find (' ') != string::npos) {
string new = sen.substr(0,i);
}
cout << "Substrings:" << new << endl;
}
Thank you! Any kind of help is appreciated!
new is a keyword in C++, so first step is to not use that as a variable name.
After that, you need to put your output statement in the "if" block, so that it can actually be allowed to access the substring. Scoping is critical in C++.
First: this cannot compile because new is a language keyword.
Then you have a loop running through every character in the string so you shouldn't need to use std::string::find. I would use std::string::find, but then the loop condition should be different.
This doesn't use substr and find, so if this is homework and you have to use that then this won't be a good answer... but I do believe it's the better way to do what you're asking in C++. It's untested but should work fine.
//Create stringstream and insert your whole sentence into it.
std::stringstream ss;
ss << sen;
//Read out words one by one into a string - stringstream will tokenize them
//by the ASCII space character for you.
std::string myWord;
while (ss >> myWord)
std::cout << myWord << std::endl; //You can save it however you like here.
If it is homework you should tag it as such so people stick to the assignment and know how much to help and/or not help you so they don't give it away :)
No need to iterate over the string, find already does this. It starts to search from the beginning by default, so once we found a space, we need to start the next search from this found space:
std::vector<std::string> words;
//find first space
size_t start = 0, end = sen.find(' ');
//as long as there are spaces
while(end != std::string::npos)
{
//get word
words.push_back(sen.substr(start, end-start));
//search next space (of course only after already found space)
start = end + 1;
end = sen.find(' ', start);
}
//last word
words.push_back(sen.substr(start));
Of course this doesn't handle duplicate spaces, starting or trailing spaces and other special cases. You would actually be better off using a stringstream:
#include <sstream>
#include <algorithm>
#include <iterator>
std::istringstream stream(sen);
std::vector<std::string> words(std::istream_iterator<std::string>(stream),
std::istream_iterator<std::string>());
You can then just put these out however you like or just do it directly in the loops without using a vector:
for(std::vector<std::string>::const_iterator iter=
words.begin(); iter!=words.end(); ++iter)
std::cout << "found word: " << *iter << '\n';
I am trying to display the text of a command line inputted text file line by line. But for some reason, it skips the first word in each line after the first line.
code:
using std::cout;
using std::cin;
using std::endl;
int main (int args, char* argv[])
{
char x[100];
char y[100];
char z[100];
cin.getline(x,100) >> argv[2];
cin.getline(y,100) >> argv[2];
cin.getline(z,100) >> argv[2];
cout << x <<endl;
cout << y <<endl;
cout << z <<endl;
return 1;
}
running ./a.out < moby.txt
displays this:
CHAPTER 1. Loomings.
me Ishmael. Some years ago--never mind how long precisely--having
or no money in my purse, and nothing particular to interest me on
but the first three lines in moby.txt is this:
CHAPTER 1. Loomings.
Call me Ishmael. Some years ago--never mind how long precisely--having
little or no money in my purse, and nothing particular to interest me on
The code is omitting "Call" and "little".
I feel like this is an \n error but i have no idea how to fix it.
Thanks in advance for any help.
cin.getline(x,100) >> argv[2];
You read a line (or the first 99 characters of the line) into x. Then you skip any whitespace and read the next word into argv[2]. The first words are ending up there.
Why are you using >> argv[2]? What are you possibly trying to do with this? argv[2] may not exist and even if it does, you don't have any control over the size of the character array pointed to by argv[2], so your chances of overrunning that array are quite high.
Rather than using char arrays directly for this, use std::getline with std::string to read lines into std::string objects: it is much easier to write correct code this way. For example,
std::string x;
if (!std::getline(std::cin, x)) {
// handle input error
}
#James McNellis has already pointed to the basic problem. My advice would be:
Don't use the member-function form of getline.
Don't mix getline and >> in the same statement.
Use a loop.
I find the other C++ getline to be easier and safer to use;
string str;
getline (cin,str);
will slurp the entire line and put it into a string, which you can then play with via the many fine string methods, or stringstream if you want to do I/O on parts of the string.
This is what I chose to do to make sure I am not missing any words or letters when I Use getline:
cout << "\nEnter some words: ";
while (getline(cin,myString)){
getline(cin,myString);
break;
};