Find line by one word in vector - c++

Trying to find a line by one word in a vector.
For example:
In a file some data,like:
ctrl+a move,find
ctrl+c copy,group
ctrl+z take,give
all letters are small.
Then I tried to read a file in vector - it's okay
Then the user want to input : move
**I want that if the user input move, I find a line in vector,which has the word move and do something with this line.(for example: erase)*
But what do I do wrong , because my loop stops on zero and it reads only the first string of a file?
code is below:
void HotMap::test(std::string str)
{
std::string line;
std::vector<std::string> vec_keys;
std::string file_name_keys("read_keys.txt");
std::ifstream file_keys(file_name_keys, std::ios::in);
std::vector<std::string>::iterator iter_vec;
while (std::getline(file_keys, line))
{
for (auto & c : line) c = tolower(c);
vec_keys.push_back(line);
}
for (int i = 0; i < 3; i++)
{
vec_keys[i].find(str);
if (vec_keys[i].find(str))
{
std::string found_str;
std::cout << "Found:" << vec_keys[i];
//Just help to find the line.....
break;
}
}
}

Read the ref of string::find:
Return Value
The position of the first character of the first match. If no matches were found, the function returns string::npos.
So, try this instead:
if (vec_keys[i].find(str) != std::string::npos)
std::cout << "Found:" << vec_keys[i];

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.

C++ Read in a file like a grid

I'm coding in C++ and I'm trying to read in a file that I'd like to access certain chars at later. As in, what is the char at (line x, char y), at any given point in the file.
My only thought right now is to look for a newline character, and somehow index them so that I can refer back to newline x, check the length of a line, and pull a char at whatever position given the line length.
I'm not sure if that is a good approach or not.
Try this (for character in line "lineNum" and column "columnNum"):
ifstream inf;
inf.open(filename); //filename being c-string
string str;
for (int i = 0; i < lineNum; i++)
{
std::getline(inf, str);
}
This way "str" stores the line you are interested in (automatically checks for newline character and stops).
Then you can use:
char chr = str[columnNum];
to store the character you want in "chr" variable. And don't forget:
inf.close();
Unfortunately, to my knowledge you need to repeat this process every time you want to access a character.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#define FILENAME "File.txt"
class FileGrid {
public:
typedef std::vector<std::string> Line;
typedef std::vector<std::string>::const_iterator LineIter;
typedef std::vector<std::vector<std::string>> StringMap;
typedef std::vector<std::vector<std::string>>::const_iterator StringMapIter;
void FillGrid(char* fileName) {
grid.clear();
std::ifstream in(FILENAME, std::ifstream::in);
if (!in.is_open()) {
std::cout << "problem reading " << FILENAME << std::endl;
return;
}
std::string words;
std::string word;
std::stringbuf buffer;
while (in.is_open() && std::getline(in, words)) {
std::stringstream ss(words);
Line line;
while (ss >> word) {
line.push_back(word);
}
grid.push_back(line);
}
}
void PrintGrid() {
StringMapIter b = grid.begin();
StringMapIter e = grid.end();
std::cout << "\t\tFile Content:" << std::endl;
while(b != e) {
for (unsigned int i = 0; i < b->size(); ++i) {
std::cout << b->operator[](i) << " ";
}
std::cout << std::endl;
++b;
}
}
char const & GetChar(int lineNo, int charNo) {
// LineNo checks etc
Line const & line = grid[lineNo];
for(std::string const & word : line ) {
if(charNo > word.size() + 1) {
charNo -= word.size() + 1;
}
else {
return word[charNo];
}
}
throw std::exception("charNo higher");
}
private:
StringMap grid;
};
void main() {
FileGrid grid;
grid.FillGrid(FILENAME);
grid.PrintGrid();
std::cout << grid.GetChar(0, 3); // should return first line, 4th character
}
Not the best code I've ever written but pretty much what I could do in a short time.
FileGrid handles reading and accessing the data. It reads the file line by line and stores it in a std::vector. When it finishes reading a line, it pushes that into another std::vector. In the end, we have a (sort of) 2D array of strings.
Again, not the best code and definitely not the most optimized code but the idea is still the same: read from the file line by line, separate each word and put them into an array of strings. If you can't use STL, you can dynamically create a 2D array for each line but since I don't know the specific requirements of your question, I just wrote something simple and bruteforce to show you the main way of storing grid of strings into the memory.
As long as it works. But reading the entire file into memory, if that's an option, would be simpler.

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.

Searching for a phrase in a text file c++

I'm trying to read a text file to find how many times a phrase/sentence(/substring?) occurs. I've done a real bodge job on it currently (see code below) but as you'll see, it relies on some rather clunky if statements.
I don't have access to the files I''ll be using it on at home, so I've used a file called big.txt and search for phrases like "and the" for the time being.
Ideally, I'd like to be able to search for "this error code 1" and it return the number of times it occurs. Any ideas on how I might get my code to work that way would be incredibly useful!
int fileSearch(string errorNameOne, string errorNameTwo, string textFile) {
string output; //variable that will store word from text file
ifstream inFile;
inFile.open(textFile); //open the selected text file
if (!inFile.is_open()) {
cerr << "The file cannot be opened";
exit(1);
}
if (inFile.is_open()) { //Check to make sure the file has opened correctly
while (!inFile.eof()) { //While the file is NOT at the end of the file
inFile >> output; //Send the data from the file to "output" as a string
if (output == errorNameOne) { //Check to look for first word of error code
marker = 1; //If this word is present, set a marker to 1
}
else if (marker == 1) { //If the marker is set to 1,
if (output == errorNameTwo) { //and if the word matches the second error code...
count++; //increse count
}
marker = 0; //either way, set marker to 0 again
}
}
}
inFile.close(); //Close the opened file
return count; //Function returns count of error
}
Given that your phrase can only occur once per line and the number follows the phrase after a number of spaces you can read the file line by line and use std::string::find() to see of your phrase is somewhere in the line. That will return the position of the phrase. You can then work on checking the rest of the line immediately after the phrase to test the number for 1 or 0.
This code may not be exactly what you want (still not certain of the exact specs) but hopefully it should contain enough examples of what you can do to achieve your goal.
// pass the open file stream in to this function along with the
// phrase you are looking for and the number to check
int count(std::istream& is, const std::string& phrase, const int value)
{
int count = 0;
std::string line;
while(std::getline(is, line)) // read the stream line by line
{
// check if the phrase appears somewhere in the line (pos)
std::string::size_type pos = line.find(phrase);
if(pos != std::string::npos) // phrase found pos = position of phrase beginning
{
// turn the part of the line after the phrase into an input-stream
std::istringstream iss(line.substr(pos + phrase.size()));
// attempt to read a number and check if the number is what we want
int v;
if(iss >> v && v == value)
++count;
}
}
return count;
}
int main()
{
const std::string file = "tmp.txt";
std::ifstream ifs(file);
if(!ifs.is_open())
{
std::cerr << "ERROR: Unable to open file: " << file << '\n';
return -1;
}
std::cout << "count: " << count(ifs, "Header Tangs Present", 1) << '\n';
}
Hope this helps.

Reading a file into an array

I would like to read a text file and input its contents into an array. Then I would like to show the contents of the array in the command line.
My idea is to open the file using:
inFile.open("pigData.txt")
And then to get the contents of the file using:
inFile >> myarray [size]
And then show the contents using a for loop.
My problem is that the file I am trying to read contain words and I don't know how to get a whole word as an element in the array. Also, let's say that the words are divided by spaces, thus:
hello goodbye
Could be found on the file. I would like to read the whole line "hello goodbye" into an element of a parallel array. How can I do that?
Should be pretty straightforward.
std::vector<std::string> file_contents;
std::string line;
while ( std::getline(inFile,line) )
file_contents.push_back(line);
std::vector<std::string>::iterator it = file_contents.begin();
for(; it!=file_contents.end() ; ++it)
std::cout << *it << "\n";
Edit:
Your comment about having "hello goodbye" as element zero and element one is slightly confusing to me. The above code snip will read each line of the file and store that as an individual entry in the array 'file_contents'. If you want to read it and split it on spaces that is slightly different.
For context, you could have provided a link to your previous question, about storing two lists of words in different languages. There I provided an example of reading the contents of a text file into an array:
const int MaxWords = 100;
std::string piglatin[MaxWords];
int numWords = 0;
std::ifstream input("piglatin.txt");
std::string line;
while (std::getline(input, line) && numWords < MaxWords) {
piglatin[numWords] = line;
++numWords;
}
if (numWords == MaxWords) {
std::cerr << "Too many words" << std::endl;
}
You can't have one parallel array. For something to be parallel, there must be at least two. For parallel arrays of words, you could use a declarations like this:
std::string piglatin[MaxWords];
std::string english[MaxWords];
Then you have two options for filling the arrays from the file:
Read an entire line, and the split the line into two words based on where the first space is:
while (std::getline(input, line) && numWords < MaxWords) {
std::string::size_type space = line.find(' ');
if (space == std::string::npos)
std::cerr << "Only one word" << std::endl;
piglatin[numWords] = line.substr(0, space);
english[numWords] = line.substr(space + 1);
++numWords;
}
Read one word at a time, and assume that each line has exactly two words on it. The >> operator will read a word at a time automatically. (If each line doesn't have exactly two words, then you'll have problems. Try it out to see how things go wrong. Really. Getting experience with a bug when you know what the cause is will help you in the future when you don't know what the cause is.)
while (input && numWords < MaxWords) {
input >> piglatin[numWords];
input >> english[numWords];
++numWords;
}
Now, if you really one one array with two elements, then you need to define another data structure because an array can only have one "thing" in each element. Define something that can hold two strings at once:
struct word_pair {
std::string piglatin;
std::string english;
};
Then you'll have just one array:
word_pair words[MaxWords];
You can fill it like this:
while (std::getline(input, line) && numWords < MaxWords) {
std::string::size_type space = line.find(' ');
if (space == std::string::npos)
std::cerr << "Only one word" << std::endl;
words[numWords].piglatin = line.substr(0, space);
words[numWords].english = line.substr(space + 1);
++numWords;
}
Notice how the code indexes into the words array to find the next word_pair object, and then it uses the . operator to get to the piglatin or english field as necessary.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
// This will store each word (separated by a space)
vector<string> words;
// Temporary variable
string buff;
// Reads the data
fstream inFile("words.txt");
while(!inFile.eof())
{
inFile>>buff;
words.push_back(buff);
}
inFile.close();
// Display
for(size_t i=0;i<words.size();++i) cout<<words[i]<<" ";
return 0;
}
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main ()
{
vector<string> fileLines;
string line;
ifstream inFile("pigData.txt");
if ( inFile.is_open() ) {
while ( !inFile.eof() ) {
getline(inFile, line);
fileLines.push_back(line);
}
inFile.close();
} else {
cerr << "Error opening file" << endl;
exit(1);
}
for (int i=0; i<fileLines.size(); ++i) {
cout << fileLines[i] << "\n";
}
cout << endl;
return 0;
}