Home > database >  How Can I change this code to get right output (C )
How Can I change this code to get right output (C )

Time:06-18

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";
}
  • Related