cin>>string takes input until space or new line. But getline(cin,string) takes input until new line. Again, getline(cin,string,'c') takes input until 'c'. Is there any way to ignore a few '\n' character and take a specified number of lines as input?
I tried the code below but it didn't work
int main()
{
string a;
for(int i=0;i<4;i++)
{
getline(cin,a);//take string input
}
cout<<a;
}
here for the following input
ksafj kfaskjf(\n)1st
uuiiuo akjfksad(\n)2nd
ksafj kasfj(\n)3rd
asdfed kkkl(\n) when the 4th enter comes input terminate
string a only holds "asdfed kkkl". I want it to hold all the characters, including the end-of-lines (\n).
Do you want to get the first n lines?
std::string get_n_lines(std::istream& input, const std::size_t n)
{
std::ostringstream result;
std::string line;
std::size_t i = 0;
while (std::getline(input, line) && i < n)
{
result << line << '\n';
++i
}
return result.str();
}
std::string first_4_lines = get_n_lines(std::cin, 4);
Related
everyone, here is a function I wrote to read a user input which is a vector of double of unknown size, the input must terminate when 'enter' is pressed:
vector<double> read_array()
{
vector<double> array_in;
double el;
while (!cin.get())
{
cin >> el;
array_in.push_back(el);
}
return array_in;
}
To illustrate it consider the following code:
void init() // the function that calls the read_array function
{
cout << "Enter array X: " << endl;
vector<double> X = read_array();
int l = X.size();
cout << l << endl;
}
A typical input when promted is:
1(space)2(space)3(space)4(enter)
When enter is pressed, the input terminates, and the variable 'l' is initialised but is equal to 0
However, when the enter key is pressed, the array size is 0. Debugging it makes it look like it never makes it into the loop like that.
The same routine works well if the input value is not an array.
Thanks to everyone in advance!
I don't know what you hope std::cin.get() does but based on your comment it seems you hope that it somehow deals with end of lines: it doesn't. It simply reads the next character which is unlikely to do you much good. In particular, if the character is anything but '\0' negating it will result in the boolean value false. That said, the loop should in principle work unless you only input a single digit numeric value followed (possibly after space) by a non-digit or the end of the input.
The easiest approach to deal with line-based input is to read the line into a std::string using std::getline() and then to parse the line using std::istringstream:
std::vector<double> read_array() {
std::vector<double> result;
if (std::string line; std::getline(std::cin, line)) {
std::istringstream lin(line);
for (double tmp; std::cin >> tmp; ) {
result.push_back(tmp);
}
}
return result;
}
As std::cin is only involved while reading lines, std::cin.fail() won't be set when parsing doubles fails. That is, you can read multiple lines with arrays of doubles, each of which can also be empty.
If you don't want to read an auxiliary line, you'll need to understand a bit more about how formatted input in C++ works: it starts off skipping whitespace. As newlines are whitespace you need to rather read the whitespace yourself and stop if it happens to be a newline or non-whitespace. I'd use a function doing this skipping which returns false if it reached a newline (which is still extracted):
bool skip_non_nl_ws(std::istream& in) {
for (int c; std::isspace(c = in.peek()); std::cin.ignore()) {
if (c == '\n') {
return false;
}
}
return true;
}
std::vector<double> read_array() {
std::vector<double> result;
for (double tmp; skip_non_nl_ws(std::cin) && std::cin >> result); ) {
result.push_back(tmp);
}
return result;
}
This approach has a similar property that std::ios_base::failbit won't be set. However, if any of the characters on a line can't be parsed as double the bit will set. That way you can detect input errors. The approach using std::getline() will just go on to the next line.
Trying to write a function that analyzes an input file and outputs info such as distinct characters, the average length of each word, and the number of total words. I'm having trouble figuring out how to keep track of the distinct characters in a string. As an example the line:
To be or not TO BE, THAT IS the question.
Should return 10 total words, 12 distinct characters, and 3.2 average word length.
This is the code I have so far:
void fileInfo(const string& fileName)
{
ifstream in(fileName);
if (in.fail())
{
cout << "Error, bad input file.";
}
string line = "";
int wordTotal = 0;
while (getline(in, line))
{
istringstream ss(line);
string word = "";
while (ss >> word)
{
wordTotal++;
for (size_t i = 0, len = word.size(); i < len; i++)
{
if (word.at(i))
}
}
{
}
One solution is to use a std::unordered_set<char> to store the letters of each word. Since an unordered_set does not store duplicates, you end up with a set of distinct letters.
Second, you only want to count alphabetic characters, not punctuation or digits before plading in a set. Thus you need to filter each character to ensure it is alphabetic.
void fileInfo(const string& fileName)
{
std::unordered_set<char> cSet;
//...
while (ss >> word)
{
wordTotal++;
for (auto v : word)
{
if (std::isalpha(v))
cSet.insert(std::tolower(v));
}
}
//...
}
Live Example
The word is only inserted into the set if it is alphabetic. Also note that the letter inserted is the lower case version.
I am trying to read in from a text file a poem that contains commas, spaces, periods, and newline character. I am trying to use getline to read in each separate word. I do not want to read in any of the commas, spaces, periods, or newline character. As I read in each word I am capitalizing each letter then calling my insert function to insert each word into a binary search tree as a separate node. I do not know the best way to separate each word. I have been able to separate each word by spaces but the commas, periods, and newline characters keep being read in.
Here is my text file:
Roses are red,
Violets are blue,
Data Structures is the best,
You and I both know it is true.
The code I am using is this:
string inputFile;
cout << "What is the name of the text file?";
cin >> inputFile;
ifstream fin;
fin.open(inputFile);
//Input once
string input;
getline(fin, input, ' ');
for (int i = 0; i < input.length(); i++)
{
input[i] = toupper(input[i]);
}
//check for duplicates
if (tree.Find(input, tree.Current, tree.Parent) == true)
{
tree.Insert(input);
countNodes++;
countHeight = tree.Height(tree.Root);
}
Basically I am using the getline(fin,input, ' ') to read in my input.
I was able to figure out a solution. I was able to read in an entire line of code into the variable line, then I searched each letter of the word and only kept what was a letter and I stored that into word.Then, I was able to call my insert function to insert the Node into my tree.
const int MAXWORDSIZE = 50;
const int MAXLINESIZE = 1000;
char word[MAXWORDSIZE], line[MAXLINESIZE];
int lineIdx, wordIdx, lineLength;
//get a line
fin.getline(line, MAXLINESIZE - 1);
lineLength = strlen(line);
while (fin)
{
for (int lineIdx = 0; lineIdx < lineLength;)
{
//skip over non-alphas, and check for end of line null terminator
while (!isalpha(line[lineIdx]) && line[lineIdx] != '\0')
++lineIdx;
//make sure not at the end of the line
if (line[lineIdx] != '\0')
{
//copy alphas to word c-string
wordIdx = 0;
while (isalpha(line[lineIdx]))
{
word[wordIdx] = toupper(line[lineIdx]);
wordIdx++;
lineIdx++;
}
//make it a c-string with the null terminator
word[wordIdx] = '\0';
//THIS IS WHERE YOU WOULD INSERT INTO THE BST OR INCREMENT FREQUENCY COUNTER IN THE NODE
if (tree.Find(word) == false)
{
tree.Insert(word);
totalNodes++;
//output word
//cout << word << endl;
}
else
{
tree.Counter();
}
}
This is a good time for a technique I've posted a few times before: define a ctype facet that treats everything but letters as white space (searching for imbue will show several examples).
From there, it's a matter of std::transform with istream_iterators on the input side, a std::set for the output, and a lambda to capitalize the first letter.
You can make a custom getline function for multiple delimiters:
std::istream &getline(std::istream &is, std::string &str, std::string const& delims)
{
str.clear();
// the 3rd parameter type and the condition part on the right side of &&
// should be all that differs from std::getline
for(char c; is.get(c) && delims.find(c) == std::string::npos; )
str.push_back(c);
return is;
}
And use it:
getline(fin, input, " \n,.");
You can use std::regex to select your tokens
Depending on the size of your file you can read it either line by line or entirely in an std::string.
To read the file you can use :
std::ifstream t("file.txt");
std::string sin((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
and this will do the matching for space separated string.
std::regex word_regex(",\\s]+");
auto what =
std::sregex_iterator(sin.begin(), sin.end(), word_regex);
auto wend = std::sregex_iterator();
std::vector<std::string> v;
for (;what!=wend ; wend) {
std::smatch match = *what;
V.push_back(match.str());
}
I think to separate tokens separated either by , space or new line you should use this regex : (,| \n| )[[:alpha:]].+ . I have not tested though and it might need you to check this out.
I am able to input string using the following code:
string str;
getline(cin, str);
But I want to know how to put an upper limit on the number of words that can be given as input.
You cannot do what you are asking with just getline or even read. If you want to limit the number of words you can use a simple for loop and the stream in operator.
#include <vector>
#include <string>
int main()
{
std::string word;
std::vector<std::string> words;
for (size_t count = 0; count < 1000 && std::cin >> word; ++count)
words.push_back(word);
}
This will read up to 1000 words and stuff them into a vector.
getline() reads characters and has no notion of what a word is. The definition of a word is likely to change with context and language. You'll need to read a stream one character at a time, extracting words that match your definition of a word and stop when you have met your limit.
You can either read one character at a time, or only process 1000 characters from your string(s).
You may be able to set a limit on std::string and use that.
Following will read only count no words separated by spaces in a vector, discarding
others.
Here punctuations are also read as "word" is separated by spaces, you need to remove them from vector.
std::vector<std::string> v;
int count=1000;
std::copy_if(std::istream_iterator<std::string>(std::cin),
// can use a ifstream here to read from file
std::istream_iterator<std::string>(),
std::back_inserter(v),
[&](const std::string & s){return --count >= 0;}
);
Hope this program helps you out. This code handles input ofmultiple words in a single line as well
#include<iostream>
#include<string>
using namespace std;
int main()
{
const int LIMIT = 5;
int counter = 0;
string line;
string words[LIMIT];
bool flag = false;
char* word;
do
{
cout<<"enter a word or a line";
getline(cin,line);
word = strtok(const_cast<char*>(line.c_str())," ");
while(word)
{
if(LIMIT == counter)
{
cout<<"Limit reached";
flag = true;
break;
}
words[counter] = word;
word = strtok(NULL," ");
counter++;
}
if(flag)
{
break;
}
}while(counter>0);
getchar();
}
As of now, this program has the limit to accept only 5 words and put it in a string array.
Use the following function:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961%28v=vs.85%29.aspx
You can specify the third argument to limit the amount of read characters.
I'm making a program which is getting inputs from the user, while each input contains ints delimited with spaces. e.g "2 3 4 5".
I implemented the atoi function well, but, whenever I try to run on the string and "skip" on the spaces I get a runtime error:
for(int i=0, num=INIT; i<4; i++)
{
if(input[i]==' ')
continue;
string tmp;
for(int j=i; input[j]!=' '; j++)
{
//add every char to the temp string
tmp+=input[j];
//means we are at the end of the number. convert to int
if(input[i+1]==' ' || input[i+1]==NULL)
{
num=m_atoi(tmp);
i=j;
}
}
}
In the line 'if(input[i+1]==' '.....' I get an exception.
Basically, I'm trying to insert just "2 2 2 2".
I realized that whenever I try to compare a real space in the string and ' ', the exception raises.
I tried to compare with the ASCII value of space which is 32 but that failed too.
Any ideas?
The problem is that you don't check for the end of the string in your main loop:
for(int j=i; input[j]!=' '; j++)
should be:
for(int j=i; input[j]!=0 && input[j]!=' '; j++)
Also, don't use NULL for the NUL char. You should use '\0' or simply 0. The macro NULL should be used only for pointers.
That said, it may be easier in your case to just use strtol or istringstream or something similar.
Not an answer to the question.
but two big for a comment.
You should note the C++ stream library automatically reads and decodes int from a space separated stream:
int main()
{
int value;
std::cin >> value; // Reads and ignores space then stores the next int into `value`
}
Thus to read multiple ints just put it in a loop:
while(std::cin >> value) // Loop will break if user hits ctrl-D or ctrl-Z
{ // Or a normal file is piped to the stdin and it is finished.
// Use value
}
To read a single line. That contains space separated values just read the line into a string (convert this to a stream then read the values.
std::string line;
std::getline(std::cin, line); // Read a line into a string
std::stringstream linestream(line); // Convert string into a stream
int value;
while(linestream >> value) // Loop as above.
{
// Use Value
}