-1

I'm trying to count vowels in a book "War and Peace" by Lev Tolstoi with 4 different methods:

  1. Using Count_if/find
  2. Using Count_if/for
  3. for/find 4.for/for

The programm also calculates time it takes for every method to get the number of vowels. I'm using a russian version of the book as a reference so all the vowels are taken from cyrillic alphabet. Here is the code:

#include <chrono>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <Windows.h>
#include <string>
#include <fstream>
#include <iterator>


class Timer
{
private:
    using clock_t = std::chrono::high_resolution_clock;
    using second_t = std::chrono::duration<double, std::ratio<1> >;
    std::string m_name;
    std::chrono::time_point<clock_t> m_beg;
    double elapsed() const
    {
        return std::chrono::duration_cast<second_t>(clock_t::now()
            - m_beg).count();
    }
public:
    Timer() : m_beg(clock_t::now()) { }
    Timer(std::string name) : m_name(name), m_beg(clock_t::now()) { }
    void start(std::string name) {
        m_name = name;
        m_beg = clock_t::now();
    }
    void print() const {
        std::cout << m_name << ":\t" << elapsed() * 1000 << " ms" << '\n';
    }
};

const std::string vowels = "аеёиоуыэюяАЕЁИОУЫЭЮЯ";

bool containVowel(const std::string& s, const char& a)
{
    for (size_t i = 0; i < s.size(); i++)
    {
        if (a == s[i])
        {
            return true;
        }
        return false;
    }
}

void ForFor(std::ifstream& ifs, std::string& ww)
{   
    size_t count = 0;
    Timer t1("for for");
    while (ifs >> ww)
    {
        for (size_t i = 0; i < ww.size(); i++)
        {
            if (containVowel(vowels, ww[i]))
            {
                count++;
            }
        }
    }
    t1.print();
    std::cout << count << std::endl;
}

//bool findVowel(char c)
//{
//    return vowels.find(c) != std::string::npos;
//}

void CountIfFind(std::ifstream& ifs, std::string& ww) // not sure what is the way to cout count here...
{

    Timer t("count_if/find");
    while (ifs >> ww)
    {

        size_t count = std::count_if(ww.begin(), ww.end(), [&](char c) {return vowels.find(c) != std::string::npos; });

    }
    t.print();
    
}

void CountIfFor(std::ifstream& ifs, std::string& ww) // not sure what is the way to cout count here...
{

    Timer t("count_if/for");

    while (ifs >> ww)
    {
        for (size_t i = 0; i < vowels.size(); i++)
        {
            auto count = std::count_if(ww.begin(), ww.end(), [&](char c) {return c == vowels[i]; });

        }
    }
    t.print();

}

void ForFind(std::ifstream& ifs, std::string& ww)
{
    char c{};
    int count = 0;
    Timer t("for/find");
    while (ifs >> ww)
    {
        for (size_t i = 0; i < ww.size(); i++)
        {
            if (vowels.find(c) != std::string::npos)
            {
                count++;
            }
        }
    }
    t.print();
    std::cout << count << std::endl;
}

int main()
{
    setlocale(LC_ALL, "ru");
  SetConsoleCP(1251);
   SetConsoleOutputCP(1251);

   std::ifstream ifs;

   
   ifs.open("Толстой Лев. Война и мир. Книга 1 - royallib.ru.txt");

   if (ifs.is_open())
   {
       std::string ww;



           ForFor(ifs, ww);

           CountIfFind(ifs,ww);

           CountIfFor(ifs,ww);
           ForFind(ifs, ww);

       ifs.close();
   }
   else
   {
       std::cout << "Can't open the file!" << std::endl;
   }
}

Function ForFor works just fine but 3 other don't work (they don't show count but show time though). I'm guessing there is a problem with parsing the file, though I'm not sure because of my inexperience. Will be hoping for your help!) Thank you all, in advance.

EDIT:Ok so now I'm sure the issue is in while(ifs>>ww). ForFor was the first function in the main so it worked, I tried commenting it and the next one CountIfFind started working. But when I delete while in every function and use it in main like: while(ifs>>ww) {ForFor(ww); CountIfFind(ww); CountIfFor(ww); ForFind(ww);} It doesn't work at all... How do I fix it?

starball
  • 20,030
  • 7
  • 43
  • 238
Zetton
  • 19
  • 4
  • 2
    "This is my first programming language and I'm a total newbie" - C++ is an insanely complicated language. Prepare to read *lots* of [books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) and spend the next 4-5 years to master it to a reasonable degree (if you use it (almost) daily - not kidding). – Jesper Juhl Oct 13 '22 at 13:45
  • 1
    This might be a good opportunity to learn about debugger - step through your code and see what really happens, why is the count not being shown. – Quimby Oct 13 '22 at 13:46
  • 2
    [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) – Jesper Juhl Oct 13 '22 at 13:47
  • you aren't printing anything but time in CountIfFind/CountIfFor. ForFind should always print a count if it is called, even if it is broken, since count is initialized to 0. That is a problem you can address – Dorito Johnson Oct 13 '22 at 13:55
  • 1
    I don't know if Russian has an extended ASCII to have those special characters available in a single `char`... Encoding is a complex domain. With unicode, utf-8 you cannot know from a **single** `char` if it is a voyel (except for `"aeiouy"`)... – Jarod42 Oct 13 '22 at 13:55
  • 2
    `return false;` in `containVowel` is misplaced, you don't actually **loop**. – Jarod42 Oct 13 '22 at 13:57
  • 1
    @JesperJuhl yea, I knew it before I took it up. But I always wanted to become a game developer and I need C++ for this dream to become true) So wish me good luck) – Zetton Oct 13 '22 at 15:10
  • @Jarod42 actually it works fine. In ForFor function it counted vowels without problems. – Zetton Oct 13 '22 at 15:11
  • 1251 (https://en.wikipedia.org/wiki/Windows-1251) is an extended ASCII codepage. If ForFor works, then probably also does (at least) the input for the other methods. – Sebastian Oct 13 '22 at 15:12
  • @DoritoJohnson Yea it prints 0. Each one of the functions prints time, the only issue is counting vowels) – Zetton Oct 13 '22 at 15:13
  • @Quimby yea, I checked it with a debugger and it skips code after while(ifs>>ww) in every function except for ForFor function for some reason... Edit: Ok so now I'm sure the issue is in while(ifs>>ww). ForFor was the first function in the main so it worked, I tried commenting it and the next one CountIfFind started working. But when I delete the look while and use it in main like: while(ifs>>ww) {ForFor(ifs, ww); CountIfFind(ifs,ww); CountIfFor(ifs,ww); ForFind(ifs, ww); – Zetton Oct 13 '22 at 15:17
  • ["What is the proper way to approach Stack Overflow as someone totally new to programming?"](https://meta.stackoverflow.com/q/254572/11107541) – starball Dec 18 '22 at 23:55

1 Answers1

0

So here is the correct way to do it:

class Timer
{
private:
    using clock_t = std::chrono::high_resolution_clock;
    using second_t = std::chrono::duration<double, std::ratio<1> >;
    std::string m_name;
    std::chrono::time_point<clock_t> m_beg;
    double elapsed() const
    {
        return std::chrono::duration_cast<second_t>(clock_t::now()
            - m_beg).count();
    }
public:
    Timer() : m_beg(clock_t::now()) { }
    Timer(std::string name) : m_name(name), m_beg(clock_t::now()) { }
    void start(std::string name) {
        m_name = name;
        m_beg = clock_t::now();
    }
    void print() const {
        std::cout << m_name << ":\t" << elapsed() * 1000 << " ms" << '\n';
    }
};

const std::string vowels = "аеёиоуыэюяАЕЁИОУЫЭЮЯ";



size_t ForFor(std::string& ww)
{   
    size_t count = 0;
    Timer t1("for for");
        for(const auto& ch : ww)
        {
            for (const auto& vow : vowels)
            {
                if (ch == vow)
                {
                    ++count;
                    break;
                }
            }
        }

    t1.print();
    return count;
}


size_t CountIfFind(std::string& ww) 
{

    Timer t("count_if/find");

        size_t count = std::count_if(ww.begin(), ww.end(), [ & ](char c) {return vowels.find(c) != std::string::npos; });

    t.print();

    return count;

    
}

size_t CountIfFor(std::string& ww) 
{

    Timer t("count_if/for");

    

    size_t count = std::count_if(ww.begin(), ww.end(), [&](const char& c1) 
        {
            for (const auto& ch : vowels)
            {
                if (c1 == ch)
                {
                    return true;
                }
            } 
            return false;
        });

    t.print();
    return count;
}

size_t ForFind(std::string& ww)
{
    char c{};
    size_t count = 0;
    Timer t("for/find");

        for (const auto& ch :ww)
        {
            if (vowels.find(ch) != std::string::npos)
            {
                ++count;
            }
        }

    t.print();
    return count;
}
int main()
{SetConsoleCP(1251);
   SetConsoleOutputCP(1251);

   
   std::ifstream file("Толстой Лев. Война и мир. Книга 1 - royallib.ru.txt");
   file.seekg(0, std::ios::end);
   size_t size = file.tellg();
   file.seekg(0);
   std::string s(size, ' ');
   file.read(&s[0], size);
   std::cout << CountIfFind(s) << std::endl;
   std::cout << ForFor(s) << std::endl;
   std::cout << ForFind(s) << std::endl;
   std::cout << CountIfFor(s) << std:: endl;
  
}
Zetton
  • 19
  • 4