I have a problem with using binary_search, it works, but only if the whole string is inserted as the search-key
I want it to work without searching after whole string, but just a key word and return "found" if a string(search-key) is part of another string(from sorted vector of strings)
case 5: // case til søgning efter telefonnummer
cout << "Indtast telefonnummer til soegning: " << endl;
getline(cin >> ws, key);
vector<string> mylines_sorted;
for (int i = 0; i < mylines.size(); i++) {
mylines_sorted.push_back(mylines[i]); // vector of strings is transferred to new vector of strings
}
sort(mylines_sorted.begin(), mylines_sorted.end());
for (int i = 0; i < mylines.size(); i++) {
cout << mylines_sorted[i] << endl; // just a check if data is sorted
}
bool result = binary_search(mylines_sorted.begin(), mylines_sorted.end(), key);
cout << result << endl; // another check
if (result == false) {
cout << "Soegning gav intet...!" << endl;
}
else {
cout << "Soegning: " << key << " findes i datafil!" << endl;
}
break;
}
return 0;
string line;
vector<string> mylines;
while (getline(database, line)) {
mylines.push_back(line);
}
I don't know if this part is relevant, I dont think so, but I transfer data from data file to vector of strings
struct Data {
char navn[80];
char addresse[80];
int alder;
unsigned int tlf;
};
There's a very simple way to get "words" from a string: Put the string into an std::istringstream and use std::istream_iterator<std::string> to get words out of it.
Combine this with the vectors insert function to add the strings to the vector you sort and search.
For example something like this:
// For each line...
for (auto const& line : mylines)
{
// Put the line into an input string stream
std::istringstream iss(line);
// Read from the string stream, adding words to the sorted_mylines vector
sorted_mylines.insert(end(sorted_mylines),
std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>());
}
After the above, sorted_mylines will contain all the words from all the lines in mylines.
You can now sort it and search for individual words. Or just skip the sorting and do a linear search.
Considering your edit, and the structure you use, I suggest you first read the file, parse each line into the corresponding structure, and create a vector of that instead of working with lines.
Then you could easily search for either name (which I recommend you split into separate first and last name) or address (which I recommend you also split up into its distinct parts, like street name, house number, postal code, etc.).
If you split it up then it will become much easier to search for specific parts. If you want a more generic search then to a linear loop over all entries, and look in all relevant structure members.
Related
At the end of the program I output the contents of a vector, the strings were inputted from a text file. The entire vector is outputted, but how do I just output one word? I am asking this because I will later need to modify each string.
#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
ifstream in;
string line, file_name;
vector <string> phrase;
int total_words, total_letters, total_chars;
cout << "PIG LATIN PROGRAM" << endl;
cout << "Which file are you accessing? : ";
cin >> file_name;
in.open(file_name);
if (in.fail()) cout << "\nFile not found!" << endl;
while(getline(in, line)) phrase.push_back(line);
for(int i = 0; i < phrase.size(); i++){
int limit = phrase.size() - 1;
while(i < limit && phrase[i] == phrase[i]){
i++;
}
cout << phrase[i];
}
You could start by splitting the line in phrase[i] at points there's whitespace:
std::istringstream iss{phrase[i]};
std::vector<std::string> words;
std::string word;
while (iss >> word)
words.push_back(std::move(word));
std::istringstream creates an input stream - a bit like cin - that contains the full line of text read from your file and stored in phrase[i]. If you then use >> word it will extract one whitespace-delimited word of text at a time.
Say your line/phrase[i] input contained "the blue socks were her favourites", it'll be split nicely into words. If there is also punctuation in the line, some of the strings in words will embed that punctuation, e.g. "world.". If you care about that, you can learn to use std::string member functions to search in and edit the strings.
In the case of punctuation you could use
std::erase(std::remove_if(word.begin(), word.end(), std::ispunct), word.end()) to remove it (further details/explanation).
phrase[i] == phrase[i]
Well, that's just redundant. This will always return true for a vector holding strings.
for(int i = 0; (...); i++){
while( (...) ){
i++;
}
}
You are modifying variable i twice in this a single for loop. Once in the third parameter of for, and once in an inner while loop. It's almost never a good idea.
What's happening here is that you set i=0, then immediately set it to point to the last element of a vector (as the second condition in while is always true).
Then you print this element to console, which is the last line of your text file.
What you want to do, is:
1. Load text file line by line into a vector.
2. Each element of vector will hold a single line.
3. Split each line into a vector of WORDS (space separated).
4. Work with the resulting vector.
Or pheraps:
1. Load file word by word at the beginning.
vector<string> words;
copy( istream_iterator<string>{YourFileStream}, istream_iterator<string>{}, back_inserter{words} ); // this will copy the content of file directly into vector, white-space-separated (no need for while loop to do it)
for ( auto i = phrase.begin(); i != phrase.end(); ++i ) // it's the proper c++ way of iterating over a vector. very similar, but variable i will point to every element of vector in order ( not just to the index of an element )
{
// do some work on *i. at least:
std::cout << *i; // dereference operator (*) is needed here, since i doesn't hold index of an element, it's a "pointer" to an element
}
If you need the first approach ( to differentiate between words in different lines ), here you can find some excellent ways to separate a string by any delimeter (space, for example): The most elegant way to iterate the words of a string
ifstream f("events.txt");
if (f.is_open())
{
string l,t;
string myArray[5];
int i = 0;
while (getline(f, l))
{
getline(stringstream(l), t, ',');
cout << t << endl;
myArray[i] = t;
cout << myArray[i] << endl;
i = i + 1;
}
So I have a file called 'events.txt' that contains:
An angry orc hits you with his weapon!,-50
A mage casts an evil spell on you!,-20
You found a health potion!,25
An enemy backstabs you from the shadows!,-40
You got eaten by a Dragon!,-1000
This part of the program so far prints out the sentence up to the comma and stores it into an array.
My problem is I also want to access the number in some way and store it into another array or to use it when the event occurs, as it'll be used to lower player HP.
Thanks in advance!
A simple way to do this:
Define a struct to store your data:
struct Event {
std::string message;
int number;
}
(Don't store both items in separate arrays, they belong together.)
Create a vector of this struct and add the items to it:
std::vector<Event> events;
while (getline(f, l)) {
size_t pos = l.find(',');
Event e;
e.message = l.substr(0, pos);
e.number = std::stoi(l.substr(pos+1));
events.push_back(e);
}
However this assumes that the string has exactly one comma. If you want to be more flexible, use std::strtok or regular expressions.
Another recommendation: Separate I/O from parsing. Don't try to read data types like int directly from the input stream, as suggested in one of the comments. Instead, read the whole line or whatever your parsing unit is and then do the parsing. This makes your code more readable and simplifies error handling and debugging.
I have been trying to make an algorithm that would read a file "TESTDATA" and then arrange the data in an array that would output something like this
ONE LETTER WORDS IN FILE = 1
TWO LETTER WORDS IN FILE = 45
THREE LETTER WORDS IN FILE = 27
FOUR LETTER WORDS IN FILE = 12
I'm not asking for an exact code, I just can't figure out how to approach this problem as I am very new to c++.
here is what I've done uptill now, I can only read the file;
ifstream fin("file.txt");
if (fin.is_open())
{
while (getline(fin, string str))
{
cout << fileline << endl;
}
fin.close();
I suggest you use either a std::vector or a std::map. The vector is more efficient accessing, but requires overhead to get it started.
std::string word;
std::map<unsigned int, unsigned int> data;
/...
while (fin >> word)
{
const unsigned int length = word.length();
data[length]++;
}
The lengths and the number of words with those lengths can be printed out using std::map iterators. This is left as an exercise for the reader and OP.
Edit 1: Vectors
With a vector, the word length will be used as an index. The number of occurrences is accessed by using the word length.
std::string word;
std::vector<unsigned int> data(128); // Reserve space for up to 128 length words.
// ...
while (fin >> word)
{
const unsigned int length = word.length();
data[length]++;
}
// To print:
// ...
cout << index << " letter words in file: " << data[index] << "\n";
//...
So essentially what you want to do is read in the whole file, and then split the file by spaces (" ") into a Vector. Then you can simply write a quick for loop saying something like this (syntax may not be perfect):
for (int i=0;i<vec.size;i++){
cout << vec[i].length(); //number of letters in each word
}
So I'm having trouble grabbing a word from document1 and comparing it to the list of words in document2. So when I run the program, the first word of document1 is comparing to the list of words of document2, but the next word in document1 isn't comparing to the list in document2. I'm not sure what the problem is... Does it have something to do with the .eof() function?
string typedString, actualString, document1 = "A.txt", document2 = "Dictionary.txt";
ifstream observeDoc, actualDoc;
observeDoc.open(document1);
actualDoc.open(document2);
while (observeDoc.is_open())
{
while (true)
{
observeDoc >> typedString;
if (observeDoc.eof()) break;
cout << typedString << endl;
while (true)
{
actualDoc >> actualString;
if (actualDoc.eof())
{
actualDoc.open(document1);
break;
}
cout << '\t' << actualString << endl;
}
}
if (observeDoc.eof()) break;
}
observeDoc.close();
actualDoc.close();
OUTPUT:
You need to go back to the beginning of the file.
you can use: observeDoc.seekg(0,ios::beg);
A better solution is to read all the words of the 1st file to an object from type std::set<std::string>, and for each word in the 2nd file check for existence in the set. In this way you move just once on each file, and no need to rewind.
std::set<std::string> words;
observeDoc.open(document1);
while (observeDoc >> typedString){
words.insert(typedString);
}
observeDoc.close();
actualDoc.open(document2);
while(actualDoc >> actualString){
if (words.find( actualString )!= words.end()){
//word exists in observer doc!
}
}
actualDoc.close();
Your problem is that actualDoc isn't resetting properly at the end of your loops. Also, your loop syntax could be way cleaner. Try this:
string typedString, actualString, document1 = "A.txt", document2 = "Dictionary.txt";
ifstream observeDoc, actualDoc;
observeDoc.open(document1);
actualDoc.open(document2);
// Will stop when it reads in EOF
while (observeDoc >> typedString)
{
while (actualDoc >> actualString)
{
// Do your comparisons here
}
actualDoc.open(document2); //reset actualDoc to start from the beginning of the file
// or, as #SHR recommended, use observeDoc.seekg(0,ios::beg);
}
observeDoc.close();
actualDoc.close();
I've been trying to retrieve saved data from a text file. The data stored are both numbers, separated by a ~. I've managed to get it to print out one of the lines (the top line) however I've been unable to figure out how to proceed through the entire file.
There are only two numbers (integers) on each line, an X and Y position of another vector. The idea is to assign each integer to the respective variable in the vectors. I've not managed to get that far since I can't get it to go past line 1. But I'd thought that by having an array size of 2, and the array temporarily stores the value, assigns it to the vector, then overwrites it with the next value(s) that could work. But again not managed to get that far.
Below is the code I've been trying to use;
........
string loadZombieData;
loadFile >> loadZombieData; //Data gets read from the file and placed in the string
vector<string> result; //Stores result of each split value as a string
stringstream data(loadZombieData);
string line;
while(getline(data,line,'~'))
{
result.push_back(line);
}
for(int i = 0; i < result.size(); i++){
cout << result[i] << " ";
}
.......
Just to clarify, this is not my code, this is some code I found on Stackoverflow, so I'm not entirely certain how it all works yet. As I said, I've been trying to get it to read multiple lines, then using the for loop was going to assign the results to the other vector variables as needed. Any help is appreciated :)
Use two while loops:
std::vector<std::string> result;
std::vector<int> numbers;
std::string filename;
std::ifstream ifile(filename.c_str());
if (!ifile.is_open()) {
std::cerr << "Input file not opened! Something went wrong!" << std::endl;
exit(0);
}
std::string temp;
//loop over the file using newlines as your delimiter
while (std::getline(ifile, temp, '\n')) {
//now temp has the information of each line.
//create a stringstream initialized with this information:
std::istringstream iss(temp);//this contains the information of ONE line
//now loop over the string stream object as you would have in your code sample:
while(getline(iss, temp,'~'))
{
//at this point temp is the value of a token, but it is a string
result.push_back(temp); //note: this only stores the TOKENS as strings
//so to store the token as a int or float, you need to convert it to that
//via another stringstream:
std::istringstream ss(temp);
//if your number type is float, change it here as well as in the vector
//initialization of `numbers`:
int num = 0;
//this checks the stream to ensure that conversion occurred.
//if it did, store the number, otherwise, handle the error (quit - but, this is up to you)
//if stringstreams aren't your cup of tea, try some others (refer to this link):
//http://stackoverflow.com/questions/21807658/check-if-the-input-is-a-number-or-string-c/21807705#21807705
if (!(ss >> num).fail()) {
numbers.push_back(num);
}
else {
std::cerr << "There was a problem converting the string to an integer!" << std::endl;
}
}
}
Note: this version stores the numbers verbatim: i.e. without a sense of how many numbers were on a line. However, that is reconcilable as all you have to do is output n numbers per line. In your case, you know every 2 numbers will be represent the numbers in a line.
This requires:
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>