Program should take input word from user and print out all the words in file with only one letter difference. For example: if input is: "way" output should be [say, may, day, war, waw, wax, was...] My code is finding words only with exact word which inputed. Like if input is "start", output is [restart, startup, started...] How can I change it to get output like above example? Here is a code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void fileRead(vector<string>& v, ifstream& fin) {
string line;
while (getline(fin, line)) {
v.push_back(line);
}
}
void search(vector<string>& v, string word) {
for (int i = 0; i < v.size(); i ) {
int index = v[i].find(word);
if (index != -1)
cout << v[i] << endl;
}
}
int main() {
vector<string> wordVector;
ifstream fin("text.txt");
if (!fin) {
cout << "text.txt can't opened" << endl;
return 0;
}
fileRead(wordVector, fin);
fin.close();
cout << "reading text.txt." << endl;
while (true) {
cout << "Input a word: >>";
string word;
getline(cin, word);
if (word == "exit")
break;
search(wordVector, word);
}
cout << "Terminated" << endl;
}
CodePudding user response:
I wrote this function find_all_alternate
to find all possible alternate of a given word.
I've taken the list of words from here
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
#include <iterator>
#include <set>
// type alias
using word_list_t = std::vector<std::string>;
using word_t = std::string;
// find all alternative occurrence of a word in the given list
void find_all_alternate(word_list_t &list, word_t word)
{
word_list_t search_list;
// Filter out bigger words
std::copy_if(list.begin(), list.end(),
std::back_inserter(search_list),
[=](auto s){
return s.size() == word.size();
});
auto len = word.size();
std::set<std::string> results;
while(len--) {
std::string alt = word.substr(1, word.size()-1);
for(const auto& w : search_list) {
auto found = w.find(alt);
if(found != std::string::npos) {
results.insert(w);
}
}
std::rotate(word.begin(), word.begin() 1, word.end());
}
std::cout << "All possible alternatives of word '" << word << "' are: " << std::endl;
for(const auto &s : results) std::cout << s << std::endl;
std::cout << std::endl;
}
int main(int argc, char *argv[])
{
if(argc != 2) {
std::cerr << "ERROR: Run the program as follows\n";
std::cerr << "./word_search <word>\n";
return -1;
}
std::string word_to_search = argv[1];
std::ifstream in_file("words.txt", std::ios::in);
if(!in_file.is_open()) {
std::cerr << "Unable to open words.txt file\n";
return -1;
}
std::string word;
word_list_t word_list;
while(in_file >> word) {
word_list.push_back(word);
}
in_file.close();
find_all_alternate(word_list, word_to_search);
}
Compilation and running
g -Wall -Wextra -Wpedantic -std=c 17 word_search.cpp -o word_search
./word_search say
Output
All possible alternatives of word 'say' are:
aye
bay
day
gay
hay
isa
jay
kay
lay
may
pay
ray
sad
sam
san
sao
sap
sas
sat
saw
say
sys
CodePudding user response:
Your program shows this result, because the std::string
find function will only look for an exact match of a substring.
What you want is to calculate the distance of 2 strings and then show those with a distance of 1.
For calculating the distance, generally the well known Levensthein algorithm is used.
I showed an implementation already in my answers here and here.
With that, your solution can be modified to
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <numeric>
using namespace std;
// Distance between 2 strings
size_t levensthein(const std::string& string1, const std::string& string2)
{
// First get the string lengths
const size_t lengthString1{ string1.size() };
const size_t lengthString2{ string2.size() };
// If one of the string length is 0, then return the length of the other
// This results in 0, if both lengths are 0
if (lengthString1 == 0) return lengthString2;
if (lengthString2 == 0) return lengthString1;
// Initialize substitition cost vector
std::vector<size_t> substitutionCost(lengthString2 1);
std::iota(substitutionCost.begin(), substitutionCost.end(), 0);
// Calculate substitution cost
for (size_t indexString1{}; indexString1 < lengthString1; indexString1) {
substitutionCost[0] = indexString1 1;
size_t corner{ indexString1 };
for (size_t indexString2{}; indexString2 < lengthString2; indexString2) {
size_t upper{ substitutionCost[indexString2 1] };
if (string1[indexString1] == string2[indexString2]) {
substitutionCost[indexString2 1] = corner;
}
else {
const size_t temp = std::min(upper, corner);
substitutionCost[indexString2 1] = std::min(substitutionCost[indexString2], temp) 1;
}
corner = upper;
}
}
return substitutionCost[lengthString2];
}
void fileRead(vector<string>& v, ifstream& fin) {
string line;
while (getline(fin, line)) {
v.push_back(line);
}
}
void search(vector<string>& v, string word) {
for (int i = 0; i < v.size(); i ) {
int distance = levensthein(word,v[i]);
if (distance == 1)
cout << v[i] << endl;
}
}
int main() {
vector<string> wordVector;
ifstream fin("text.txt");
if (!fin) {
cout << "text.txt can't opened" << endl;
return 0;
}
fileRead(wordVector, fin);
fin.close();
cout << "reading text.txt." << endl;
while (true) {
cout << "Input a word: >>";
string word;
getline(cin, word);
if (word == "exit")
break;
search(wordVector, word);
}
cout << "Terminated" << endl;
}
And if you want to convert this to more modern C , you can also use:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <numeric>
#include <algorithm>
// Distance between 2 strings
size_t levensthein(const std::string& string1, const std::string& string2)
{
// First get the string lengths
const size_t lengthString1{ string1.size() };
const size_t lengthString2{ string2.size() };
// If one of the string length is 0, then return the length of the other
// This results in 0, if both lengths are 0
if (lengthString1 == 0) return lengthString2;
if (lengthString2 == 0) return lengthString1;
// Initialize substitition cost vector
std::vector<size_t> substitutionCost(lengthString2 1);
std::iota(substitutionCost.begin(), substitutionCost.end(), 0);
// Calculate substitution cost
for (size_t indexString1{}; indexString1 < lengthString1; indexString1) {
substitutionCost[0] = indexString1 1;
size_t corner{ indexString1 };
for (size_t indexString2{}; indexString2 < lengthString2; indexString2) {
size_t upper{ substitutionCost[indexString2 1] };
if (string1[indexString1] == string2[indexString2]) {
substitutionCost[indexString2 1] = corner;
}
else {
const size_t temp = std::min(upper, corner);
substitutionCost[indexString2 1] = std::min(substitutionCost[indexString2], temp) 1;
}
corner = upper;
}
}
return substitutionCost[lengthString2];
}
int main() {
// Open file and check, if it could be opened
if (std::ifstream fin("text.txt"); fin) {
// Read all words from the file
std::vector words(std::istream_iterator<std::string>(fin), {});
// Read words to search for, until user enters exit
std::string word{};
while (word != "exit") {
// Tell user, what to do
std::cout << "\n\nInput a word: >> ";
// Show result
if (std::getline(std::cin, word) and word != "exit")
std::copy_if(words.begin(), words.end(), std::ostream_iterator<std::string>(std::cout, "\n"), [&](const std::string& s) { return 1u == levensthein(s, word); });
}
}
else std::cerr << "\nError. Could not open source file\n\n";
}
And if there is the restriction that only words of equal length shall be shown, then you can write a simple comparison function by yourself.
This would look like:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <numeric>
#include <algorithm>
bool oneLetterDifferent(const std::string& string1, const std::string& string2) {
bool equalLength{ string1.length() == string2.length() };
unsigned int unequalCounter{};
if (equalLength) for (size_t i{}; i < string1.length(); i) {
if (string1[i] != string2[i])
unequalCounter;
}
return equalLength and (unequalCounter < 2);
}
int main() {
// Open file and check, if it could be opened
if (std::ifstream fin("text.txt"); fin) {
// Read all words from the file
std::vector words(std::istream_iterator<std::string>(fin), {});
// Read words to search for, until user enters exit
std::string word{};
while (word != "exit") {
// Tell user, what to do
std::cout << "\n\nInput a word: >> ";
// Show result
if (std::getline(std::cin, word) and word != "exit")
std::copy_if(words.begin(), words.end(), std::ostream_iterator<std::string>(std::cout, "\n"), [&](const std::string& s) { return oneLetterDifferent(s, word); });
}
}
else std::cerr << "\nError. Could not open source file\n\n";
}