getting error using regex in C++ - c++

Given input has 4 lines and I am supposed to find how many lines have word hacker
4
I love #hacker
I just scored 27 points in the Picking Cards challenge on #Hacker
I just signed up for summer cup #hacker
interesting talk by hari, co-founder of hacker
The answer is 4 but I get it as 0.
int main() {
int count = 0,t;
cin >> t;
string s;
bool ans;
while(t--){
cin >> s;
smatch sm;
regex rgx("hacker",regex_constants::icase);
ans = regex_match(s,sm,rgx);
if(ans){
count += 1;
}
}
cout << ans << endl;
return 0;
}

Your while loop only runs t times, and every time it only reads one word. So your program right now will only read the first three words and then terminate.
You're only matching the whole word. In the case of #hacker an #hacker, there will be no match.
I believe you want to cout count instead of ans at the end.

You should use std::getline instead to read a string (containing whitespaces).
Also, you should use std::regex_search to search for a 'partial' match (std::regex_match will only match when the regex matches the whole string).
Here's your code a little modified:
#include <regex>
#include <iostream>
#include <string>
int main() {
int count = 0,t;
std::cin >> t;
std::string s;
std::smatch sm;
std::regex rgx("hacker", std::regex_constants::icase);
for(int i = 0; i < t; ++i)
{
std::getline(std::cin, s);
while(std::regex_search(s, sm, rgx))
{
++count;
s = sm.suffix().str();
}
}
std::cout << count << std::endl;
return 0;
}

If you change your regex as follows, you will get expected result:
regex rgx("(.*)hacker(.*)",regex_constants::icase);
So it is basically comparing for the match in whole string.
Otherwise you have to use std::regex_search in place of std::regex_match
ans = regex_search(s,sm,rgx);
Demo: http://coliru.stacked-crooked.com/a/f28c2e4b315f6f0a

It looks like the first word is supposed to be the number of lines of input. But, even though it seems you want to process four lines of input, the input says 3.Question has since been edited.
You are not reading lines, but strings, which translates into individual words. Use getline() to get a line of input.
while(t--){
std::getline(std::cin, s);
//...
Your regular expression is ill-formed. It will only match if the line consists only of the word "hacker". You want to see if hacker is in the line, so make allow your pattern to match the rest of the line around the word "hacker".
regex rgx(".*hacker.*",regex_constants::icase);
When you emit your answer, it seems you want to emit count, not ans.
DEMO

Related

Replacing word in position X of a string C++

I am trying to write a function in a program that will take a string, a word and an integer and use the int as the index value and the word as the replacement value. For example, if the string is "This is a test.", the word is "example", and the number is 4, then the result would be "This is an example". This is what I have so far (I had to make multiple copies of the string because eventually, I am going to be passing it into two other functions by reference instead of as value)Right now it is using the character index instead of the word index in order to replace. How do I fix that?
#include "pch.h"
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main()
{
string Input = "";
string Word = "";
int Number = 0;
cout << "Pleas enter a string using only lower case letters. \n";
getline(cin, Input);
cout << "Please enter a word using only lower case lettersS. \n";
getline(cin, Word);
cout << "Please enter a number. \n";
cin >> Number;
string StringCopy1 = Input;
string StringCopy2 = Input;
string StringCopy3 = Input;
}
void stringFunctionValue(string StringCopy1, int Number, string Word)
{
StringCopy1.replace(Number, Word.length, Word);
return StringCopy1;
}
First thing you have to do is find the nth word.
The first thing to come to mind is using std::istringstream to pull the string apart with >> and a std::ostringstream to write the new string.
std::istringstream in(StringCopy1);
std::string token;
std::ostringstream out;
int count = 0;
while (in >> token) // while we can get more tokens
{
if (++count != number) // not the number of the token to replace
{
out << token << " "; // write the token
}
else
{
out << word << " "; // write the replacement word
}
}
return out.str();
While this is easy to write, it has two problems: It loses the correct type of whitespace in the string AND places an extra space on the end of the string. It's also kind of slow and uses a lot more memory than if you modify the string in place.
Use std::string::find_first_not_of to find the first non-whitespace character. This will be the start of the first word. Then use std::string::find_first_of to find the next whitespace character. This will be the end of the word. Alternate back and forth finding non-whitespace then whitespace until you find the beginning and ending of the nth word. std::string::replace that word. This approach requires you to write more and more complicated code, but is much more satisfying. This is why I outlined it rather than fully implementing it: To allow you the joy for yourself.
Note: void stringFunctionValue(string StringCopy1, int Number, string Word) gives you no way to provide the result back to the user. This makes for an unhelpful function. Consider returning a string rather than void.

How to count how many words are in line?Smarter way?

How to find out how many words are in line? I now that method where you count how many there are spaces. But what if someone hit 2 spaces or start line with space.
Is there any other or smarter way to solve this?
And is there any remark on my way of solving it or my code?
I solved it like this:
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
int main( )
{
char str[80];
cout << "Enter a string: ";
cin.getline(str,80);
int len;
len=strlen(str);
int words = 0;
for(int i = 0; str[i] != '\0'; i++) //is space after character
{
if (isalpha(str[i]))
{
if(isspace(str[i+1]))
words++;
}
}
if(isalpha(str[len]))
{
words++;
}
cout << "The number of words = " << words+1 << endl;
return 0;
}
The std one-liner is:
words= distance(istream_iterator<string>(istringstream(str)), istream_iterator<string>());
streams by default skip spaces (multiple also).
So if you do something like:
string word;
int numWords = 0;
while (cin >> word) ++numWords;
That should count the number of words for simple cases (not considering what the format of a word is, skipping spaces).
If you want per line, you could read first the line, create a stream from a string, and do a similar thing like this:
string line, word;
int wordCount = 0;
getline(cin, line);
stringstream lineStream(line);
while (lineStream >> word) ++wordCount;
You should not use cin.getline and should prefer the free function std::getline, which takes a string that can be grown up and prevents stack overflows (lol). Stick to the free function for better safety.
First, you need a very specific definition of "word." Most of the answers will give slightly different counts than your attempt because you're using different definitions of what constitutes a word. Your example specifically requires alpha characters in certain positions. The answers based on streams will allow any non-space character to be part of a word.
The general solution is to come up with a precise definition of a word, transform this into a regular expression or finite state machine, and then count each instance of a match.
Here's a sample state machine solution:
std::size_t CountWords(const std::string &line) {
std::size_t count = 0;
enum { between_words, in_word } state = between_words;
for (const auto c : line) {
switch (state) {
case between_words:
if (std::isalpha(c)) {
state = in_word;
++count;
}
break;
case in_word:
if (std::isspace(c)) state = between_words;
break;
}
}
return count;
}
Some test cases to consider (and that highlight the differences among the definitions of a word):
"" empty string
" " just spaces
"a"
" one "
"count two"
"hyphenated-word"
"\"That's Crazy!\" she said." punctuation between alpha characters and adjacent spaces
"the answer is 42" should the number count as a word?

Splitting sentences and placing in vector

I was given a code from my professor that takes multiple lines of input. I am currently changing the code for our current assignment and I came across an issue. The code is meant to take strings of input and separate them into sentences from periods and put those strings into a vector.
vector<string> words;
string getInput() {
string s = ""; // string to return
bool cont = true; // loop control.. continue is true
while (cont){ // while continue
string l; // string to hold a line
cin >> l; // get line
char lastChar = l.at(l.size()-1);
if(lastChar=='.') {
l = l.substr(0, l.size()-1);
if(l.size()>0){
words.push_back(s);
s = "";
}
}
if (lastChar==';') { // use ';' to stop input
l = l.substr(0, l.size()-1);
if (l.size()>0)
s = s + " " + l;
cont = false; // set loop control to stop
}
else
s = s + " " + l; // add line to string to return
// add a blank space to prevent
// making a new word from last
// word in string and first word
// in line
}
return s;
}
int main()
{
cout << "Input something: ";
string s = getInput();
cout << "Your input: " << s << "\n" << endl;
for(int i=0; i<words.size(); i++){
cout << words[i] << "\n";
}
}
The code puts strings into a vector but takes the last word of the sentence and attaches it to the next string and I cannot seem to understand why.
This line
s = s + " " + l;
will always execute, except for the end of input, even if the last character is '.'. You are most likely missing an else between the two if-s.
You have:
string l; // string to hold a line
cin >> l; // get line
The last line does not read a line unless the entire line has non-white space characters. To read a line of text, use:
std::getline(std::cin, l);
It's hard telling whether that is tripping your code up since you haven't posted any sample input.
I would at least consider doing this job somewhat differently. Right now, you're reading a word at a time, then putting the words back together until you get to a period.
One possible alternative would be to use std::getline to read input until you get to a period, and put the whole string into the vector at once. Code to do the job this way could look something like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
int main() {
std::vector<std::string> s;
std::string temp;
while (std::getline(std::cin, temp, '.'))
s.push_back(temp);
std::transform(s.begin(), s.end(),
std::ostream_iterator<std::string>(std::cout, ".\n"),
[](std::string const &s) { return s.substr(s.find_first_not_of(" \t\n")); });
}
This does behave differently in one circumstance--if you have a period somewhere other than at the end of a word, the original code will ignore that period (won't treat it as the end of a sentence) but this will. The obvious place this would make a difference would be if the input contained a number with a decimal point (e.g., 1.234), which this would break at the decimal point, so it would treat the 1 as the end of one sentence, and the 234 as the beginning of another. If, however, you don't need to deal with that type of input, this can simplify the code considerably.
If the sentences might contain decimal points, then I'd probably write the code more like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
class sentence {
std::string data;
public:
friend std::istream &operator>>(std::istream &is, sentence &s) {
std::string temp, word;
while (is >> word) {
temp += word + ' ';
if (word.back() == '.')
break;
}
s.data = temp;
return is;
}
operator std::string() const { return data; }
};
int main() {
std::copy(std::istream_iterator<sentence>(std::cin),
std::istream_iterator<sentence>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Although somewhat longer and more complex, at least to me it still seems (considerably) simpler than the code in the question. I guess it's different in one way--it detects the end of the input by...detecting the end of the input, rather than depending on the input to contain a special delimiter to mark the end of the input. If you're running it interactively, you'll typically need to use a special key combination to signal the end of input (e.g., Ctrl+D on Linux/Unix, or F6 on Windows).
In any case, it's probably worth considering a fundamental difference between this code and the code in the question: this defines a sentence as a type, where the original code just leaves everything as strings, and manipulates strings. This defines an operator>> for a sentence, that reads a sentence from a stream as we want it read. This gives us a type we can manipulate as an object. Since it's like a string in other ways, we provide a conversion to string so once you're done reading one from a stream, you can just treat it as a string. Having done that, we can (for example) use a standard algorithm to read sentences from standard input, and write them to standard output, with a new-line after each to separate them.

When parsing a string using a string stream, it extracts a new line character

Description of the program : The program must read in a variable amount of words until a sentinel value is specified ("#" in this case). It stores the words in a vector array.
Problem : I use a getline to read in the string and parse the string with a stringstream. My problem is that the stringstream is not swallowing the new line character at the end of each line and is instead extracting it.
Some solutions I have thought of is to cut off the last character by creating a subset or checking if the next extracted word is a new line character, but I feel there is a better cost efficient solution such as changing the conditions for my loops.
I have included a minimized version of the overall code that reproduces the problem.
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
const int MAX_LIST_SIZE = 1000;
string str;
string list[MAX_LIST_SIZE];
int numWords = 0;
// program starts here
getline(cin, str); // read innput
stringstream parse(str); // use stringstream to parse input
while(str != "#") // read in until sentinel value
{
while(!parse.fail()) // until all words are extracted from the line
{
parse >> list[numWords]; // store words
numWords++;
}
getline(cin,str); // get next line
parse.clear();
parse.str(str);
}
// print number of words
cout << "Number of words : " << numWords << endl;
}
And a set of test input data that will produce the problem
Input:
apples oranges mangos
bananas
pineapples strawberries
Output:
Number of words : 9
Expected Output:
Number of words : 6
I would appreciate any suggestions on how to deal with this problem in an efficient manner.
Your logic for parsing out the stream isn't quite correct. fail() only becomes true after a >> operation fails, so you'll doing an extra increment each time. For example:
while(!parse.fail())
{
parse >> list[numWords]; // fails
numWords++; // increment numWords anyway
} // THEN check !fail(), but we incremented already!
All of these operations have returns that you should check as you go to avoid this problem:
while (getline(cin, str)) { // fails if no more lines in cin
if (str != "#") { // doesn't need to be a while
stringstream parse(str);
while (parse >> list[numWords]) { // fails if no more words
++numWords; // *only* increment if we got one!
}
}
}
Even better would be to not use an array at all for the list of words:
std::vector<std::string> words;
Which can be used in the inner loop:
std::string temp;
while (parse >> temp) {
words.push_back(temp);
}
The increment on numwords happens one more time than you intend at the end of each line. Use a std::vector< std::string > for your list. Then you can use list.size().

How to input text containing less than 1000 words with spaces and punctuations?

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.