Created
March 1, 2017 17:51
-
-
Save MighteeCactus/9a1708b0643eb583e52fe098999389d7 to your computer and use it in GitHub Desktop.
Unigine's C++ School entry test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Быков Александр. | |
// В общей сложности ушло часов 5. Где-то 80% времени ушло на то, | |
// чтобы нагуглить и вспомнить как пользоваться классами STL :) | |
#include <iostream> | |
#include <fstream> | |
#include <string> | |
#include <map> | |
#include <sstream> // для разбивки строки на слова | |
#include <regex> // regex и regex_replace | |
#include <iomanip> // для флагов форматирования вывода | |
#include <algorithm> // sort | |
#include <memory> // shared_ptr | |
using namespace std; | |
// Подсчитывает слова, на вход принимает ifstream | |
// Может записать результат в файл | |
// Для удаления лишних символов используется регулярное выражение | |
class WordCounter | |
{ | |
private: | |
// слова используются как ключи, чтобы проще было подсчитывать частоту | |
map<string, int> *words; | |
// для форматирования в консоли | |
int longestWord = 0; | |
// дефолтный конструктор нам не нужен | |
WordCounter() = delete; | |
public: | |
WordCounter(ifstream &file); | |
virtual ~WordCounter(); | |
void FlushToFile(ofstream &file); | |
// тут для форматированного вывода в консоль | |
friend ostream & operator<<(ostream &os, const WordCounter &wCounter); | |
}; | |
WordCounter::WordCounter(ifstream &file) | |
{ | |
words = new map<string, int>(); | |
// создаем регулярку для последующего использования | |
string rExpStr("[.,?!1-9;:].?"); | |
regex rExpression(rExpStr); | |
string line; | |
while (getline(file, line)) | |
{ | |
string strippedLine; | |
// отсеиваем не нужные символы и цифры | |
regex_replace(back_inserter(strippedLine), line.begin(), line.end(), rExpression, " "); | |
// с помощью стрима удобно разделять строку на отдельные слова | |
// и не заботиться о нескольких пробелах подряд | |
stringstream sstream(strippedLine); | |
string word; | |
// разбиваем строку на отдельные слова | |
while(sstream >> word) | |
{ | |
// переводим все слова в нижний регистр (не работает с кириллицей, | |
// если изначально не указана кодировка) | |
transform(word.begin(), word.end(), word.begin(), ::tolower); | |
// длина самого длинного слова нужна для форматирования в консоли | |
longestWord = max<int>(longestWord, word.length()); | |
// если слово уже записано, то вернется указатель на существующий объект, | |
// если нет, то добавляем | |
auto iter = words->emplace(word, 0); | |
(*iter.first).second++; | |
} | |
} | |
} | |
WordCounter::~WordCounter() | |
{ | |
delete words; | |
} | |
void WordCounter::FlushToFile(ofstream &file) | |
{ | |
// вектор с парами (слово, частота). Нужен чтобы отсортировать данные в нужном порядке | |
shared_ptr<vector<pair<string, int>>> wordPairs(new vector<pair<string, int>>(words->begin(), words->end())); | |
// компаратор для сортировки | |
auto cmp = [](const pair<string, int> & a, const pair<string, int> & b) | |
{ | |
return a.second != b.second ? a.second > b.second : a.first < b.first; | |
}; | |
sort(wordPairs->begin(), wordPairs->end(), cmp); | |
for (auto &iter : *wordPairs) | |
{ | |
file << iter.second << " " << iter.first << endl; | |
} | |
} | |
// friend чтобы можно было использовать cout (или любой другой ostream) для вывода | |
ostream & operator<<(ostream &os, const WordCounter &wCounter) | |
{ | |
for (auto &iter : *(wCounter.words)) | |
{ | |
os << "[ " << setw(wCounter.longestWord) << iter.first << setw(0) << " ]: " << iter.second << endl; | |
} | |
return os; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
// если не хватает аргументов, сообщаем | |
if (argc < 3) | |
{ | |
cout << "Usage: " << argv[0] << " <input_file_path> <output_file_path>"; | |
return 1; | |
} | |
// файл из которого будем читать | |
ifstream iFile; | |
iFile.open(argv[1], ifstream::in); | |
if ( !iFile.is_open() ) | |
{ | |
cerr << "File " << argv[1] << " can't be opened for read." << endl; | |
return 2; | |
} | |
// читаем и заполняем map | |
WordCounter counter(iFile); | |
iFile.close(); | |
cout << counter; | |
// файл куда будем скидывать результат | |
ofstream oFile; | |
oFile.open(argv[2], ofstream::out | ofstream::trunc); | |
if (!oFile.is_open()) | |
{ | |
cerr << "File " << argv[2] << " can't be opened for write." << endl; | |
return 3; | |
} | |
counter.FlushToFile(oFile); | |
oFile.close(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment