error in program "removing duplicate words from string" - c++

I used two strings one to store words and other to store the output string. The idea is to go through character by character and whenever space is encountered , push it in the newly form string after checking whether it already exists or not.
But the code is not giving any output and I am not able to find out why.
I just want to know what I am doing wrong
#include <iostream>
using namespace std;
int main() {
string str;
cin>>str;
string str1 = "";
string word = "";
for(auto x : str){
if(x == ' '){
size_t found = str1.find(word);
if(found == string::npos){
str1 += " " + word;
}
}
else
word += x;
}
cout<<str1;
}

I see three problems here:
cin >> str will only read until the next space, so you only ever process one word. Use std::getline instead:
string str;
std::getline(cin, str);
You only update str1 when you encounter a space in str, so you lose the last word unless the input ends with a space. You can simply append a space on the input before using it. For example put
str.push_back(' ');
after reading the input.
You don't clear word, so it will grow longer and longer. You can use std::string::clear() like so:
if(x == ' ') {
size_t found = str1.find(word);
if(found == string::npos){
str1 += " " + word;
}
// VVVVVVVVVV reset word buffer after word processing of word finished
word.clear();
}

Related

C++ : find word in a string, count how many times was found, then print meaning of the word

I'm doing the assignment and I'm at the end of my powers. Right now I can't figure out what's missing or what I could change.
I need the program to read me a file. If it finds the beginning of the search word, it lists the word and its meaning. If he finds it more than once, he writes only that word without meaning.
Right now, if the program finds more words, it writes the meaning for the first word and writes the word for the other words found.
I don't know what other cycle I could use. If you could help me, I would be grateful.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include<bits/stdc++.h>
using namespace std;
int main()
{
ifstream dictionary("dictionary.txt");
if(!dictionary.is_open()){
cout<< "File failed to open" << endl;
return 0;
}
int option;
cout << "1.<starting>" << endl;
cout << "4.<stop>" << endl;
cin >> option;
string find_word;
string word, meaning;
string line;
string found;
int count = 0;
if (option == 1)
{
cout << "Find the meaning of the word beginning with the characters:";
cin >> find_word;
while (getline(dictionary,line))
{
stringstream ss(line);
getline (ss, word, ';');
getline (ss, meaning, ';');
if (word.rfind(find_word, 0) != string::npos)
{
count++;
if (count <=1)
{
found = word + meaning;
cout << found << endl;
}
if (count >= 2)
{
found = word ;
cout << found << endl;
}
}
}
}
if (option == 4)
{
return 0;
}
dictionary.close();
return 0;
}
EDIT
dictionary.txt looks like this:
attention; attentionmeaning
attention; attentionmeaning2
computer; computermeaning
criminal; criminalmeaning
boat; boatmeaning
alien; alienmeaning
atter; meaning
.
.
etc.
For example input is:
Find the meaning of the word beginning with the characters: att
this is what i get now (output):
attention attentionmeaning
attention
atter
this is what i expect (desire output):
attention
attention
atter
if program find only one searching word it should write this:
Find the meaning of the word beginning with the characters: bo
output:
boat boatmeaning
As it was already suggested, while reading the file, you don't know if there will be more than one entries matching your search term. That being said, you need some intermediate structure to store all the matching entries.
After you have gathered all the results, you can easily check if the data contains more than one result, in which case you only print the "word" without the meaning. In case there is only one result, you can print the "word" together with its meaning.
The code for that could look something like this:
struct Entry {
std::string name;
std::string meaning;
bool startsWith(const std::string& str) {
return name.find(str) != std::string::npos;
}
};
Entry createEntry(const std::string& line) {
Entry entry;
std::stringstream ss(line);
std::getline(ss, entry.name, ';');
std::getline(ss, entry.meaning, ';');
return entry;
}
int main() {
std::string query = "att";
std::ifstream dictionary("dictionary.txt");
std::vector<Entry> entries;
std::string line;
while (std::getline(dictionary, line)) {
Entry entry = createEntry(line);
if (entry.startsWith(query)) {
entries.emplace_back(std::move(entry));
}
}
for (const Entry& entry : entries) {
std::cout << entry.name << (entries.size() > 1 ? "\n" : " " + entry.meaning + '\n');
}
}
This code could definitely be more optimized, but for the sake of simplicity, this should suffice.
Demo
The problem is that at the first time through the loop you do not know if there is one or more valid words that follow from your string. I would suggest you create an empty list outside the loop, and push all the word and meaning pairs that match onto the list. Then after if the size of the list is 1 you can output the word and meaning pair else use a for loop to loop through and just print the words.

I have written a function to remove spaces from a sentence but its only taking chars before the space & not considering the entire sentance

I have written a function to remove spaces from a sentence but its only taking chars before the space & not considering the entire sentence.
if I run this Out put is
Enter the string with space/ tab to trim
IamDoing very fine
Length of the String is : 8
IamDoing
I what changes I need to do get "IamDoingveryfine"
Please help, Code is as follows..."
void removeSpace(const string &str)
{
string tempStr;
string p_str = str;
int l_length = p_str.length();
cout<<"Length of the String is : "<<l_length<<endl;
for (int i=0; i<l_length; i++)
{
if(p_str[i] != ' ' || p_str[i] != '\t')
{
tempStr +=p_str[i]; //to add chars into tempstr
}
}
cout<<tempStr<<'\n';
return ;
}
The problem is not with the removespace(), problem is when you are taking the input.
It should be like this:
std::string line;
std::cout << "Enter the string with space/ tab to trim" << std::endl;
std::cin.getline (line);
I used
std::getline (std::cin,name);
the input problem is resolved with this. But in the trim function even though im checking for ' ' & '\t' im not able to block the white spaces.
the removeSpace should be missing with something.
I modified my function to get the expected answer as below
void removeSpace(const string &str)
{
string tempStr;
string p_str = str;
int l_length = p_str.length();
cout<<"Length of the String is : "<<l_length<<endl;
for (int i=0; i<l_length; i++)
{
if((p_str[i] == ' ') || (p_str[i] == '\t'))
{
continue;
}
else
{
cout<<p_str[i]<<endl;
tempStr +=p_str[i]; //to add chars into tempstr
}
}
cout<<tempStr<<'\n';
return ;
}
but while I used if(p_str[i] != ' ' || p_str[i] != '\t') function was unable to discard spaces, can anybody tell me why this difference

Find specific text in string delimited by newline characters

I want to find a specific string in a list of sentence. Each sentence is a line delimited with a \n. When the newline is reached the current search should stop and start new on the next line.
My program is:
#include <iostream>
#include <string.h>
using namespace std;
int main(){
string filename;
string list = "hello.txt\n abc.txt\n check.txt\n"
cin >> filename;
// suppose i run programs 2 times and at 1st time i enter abc.txt
// and at 2nd time i enter abc
if(list.find(filename) != std::string::npos){
//I want this condition to be true only when user enters complete
// file name. This condition also becoming true even for 'abc' or 'ab' or even for 'a' also
cout << file<< "exist in list";
}
else cout<< "file does not exist in list"
return 0;
}
Is there any way around. i want to find only filenames in the list
list.find will only find substring in the string list, but if you want to compare the whole string till you find the \n, you can tokenize the list and put in some vector.
For that, you can put the string list in std::istringstream and make a std::vector<std::string> out of it by using std::getline like:
std::istringstream ss(list);
std::vector<std::string> tokens;
std::string temp;
while (std::getline(ss, temp)){
tokens.emplace_back(temp);
}
If there are leading or trailing spaces in the tokens, you can trim the tokens before adding them to the vector. For trimming, see What's the best way to trim std::string?, find a trimming solution from there that suits you.
And after that, you can use find from <algorithm> to check for complete string in that vector.
if (std::find(tokens.begin(), tokens.end(), filename) != tokens.end())
std::cout << "found" << std::endl;
First of all I wouldn't keep the list of files in a single string, but I would use any sort of list or vector.
Then if keeping the list in a string is a necessity of yours (for some kind of reason in your application logic) I would separate the string in a vector, then cycle through the elements of the vector checking if the element is exactly the one searched.
To split the elements I would do:
std::vector<std::string> split_string(const std::string& str,
const std::string& delimiter)
{
std::vector<std::string> strings;
std::string::size_type pos = 0;
std::string::size_type prev = 0;
while ((pos = str.find(delimiter, prev)) != std::string::npos)
{
strings.push_back(str.substr(prev, pos - prev));
prev = pos + 1;
}
// To get the last substring (or only, if delimiter is not found)
strings.push_back(str.substr(prev));
return strings;
}
You can see an example of the function working here
Then just use the function and change your code to:
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
int main(){
string filename;
string list = "hello.txt\n abc.txt\n check.txt\n"
cin >> filename;
vector<string> fileList = split_string(list, "\n");
bool found = false;
for(int i = 0; i<fileList.size(); i++){
if(fileList.at(i) == file){
found = true;
}
}
if(found){
cout << file << "exist in list";
} else {
cout << "file does not exist in list";
}
return 0;
}
Obviously you need to declare and implement the function split_string somewhere in your code. Possibly before main declaration.

Reading in only letters from a text file

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.

How can I ignore the "end of line" or "new line" character when reading text files word by word?

Objective:
I am reading a text file word by word, and am saving each word as an element in an array. I am then printing out this array, word by word. I know this could be done more efficiently, but this is for an assignment and I have to use an array.
I'm doing more with the array, such as counting repeated elements, removing certain elements, etc. I also have successfully converted the files to be entirely lowercase and without punctuation.
Current Situation:
I have a text file that looks like this:
beginning of file
more lines with some bizzare spacing
some lines next to each other
while
others are farther apart
eof
Here is some of my code with itemsInArray initialized at 0 and an array of words refered to as wordArray[ (approriate length for my file ) ]:
ifstream infile;
infile.open(fileExample);
while (!infile.eof()) {
string temp;
getline(infile,temp,' '); // Successfully reads words seperated by a single space
if ((temp != "") && (temp != '\n') && (temp != " ") && (temp != "\n") && (temp != "\0") {
wordArray[itemsInArray] = temp;
itemsInArray++;
}
The Problem:
My code is saving the end of line character as an item in my array. In my if statement, I've listed all of the ways I have tried to disclude the end of line character, but I've had no luck.
How can I prevent the end of line character from saving as an item in my array?
I've tried a few other methods I have found on threads similar to this, including something with a *const char that I couldn't make work, as well as iterating through and deleting the new line characters. I've been working on this for hours, I don't want to repost the same issue, and have tried many many methods.
The standard >> operator overloaded for std::string already uses white-space as word boundary so your program can be simplified a lot.
#include <iostream>
#include <string>
#include <vector>
int
main()
{
std::vector<std::string> words {};
{
std::string tmp {};
while (std::cin >> tmp)
words.push_back(tmp);
}
for (const auto& word : words)
std::cout << "'" << word << "'" << std::endl;
}
For the input you are showing, this will output:
'beginning'
'of'
'file'
'more'
'lines'
'with'
'some'
'bizzare'
'spacing'
'some'
'lines'
'next'
'to'
'each'
'other'
'while'
'others'
'are'
'farther'
'apart'
'eof'
Isn't this what you want?
The stream's extraction operator should take care of that for you
std::ifstream ifs("file.txt");
while (ifs.good())
{
std::string word;
ifs >> word;
if (ifs.eof())
{
break;
}
std::cout << word << "\n";
}
int main()
{
char *n;
int count=0,count1=0;
ofstream output("user.txt");
output<<"aa bb cc";
output.close();
ifstream input("user.txt");
while(!input.eof())
{
count++;
if(count1<count)
cout<<" ";
count1=count;
input>>n;
cout<<n;
}
cout<<"\ncount="<<count;
getch();
}