-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mohammed almakki exercies #88
base: main
Are you sure you want to change the base?
Changes from 5 commits
2252c62
55a3c17
66b9c7d
2d7dd69
07ee0cb
5986ad4
9fab113
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
cmake_minimum_required ( VERSION 3.14 ) | ||
|
||
project(newstarter) | ||
|
||
add_subdirectory ( ex01_basics ) | ||
add_subdirectory ( ex02_oo_basics ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This directory contains the template CMake projects for each of the exercises. | ||
|
||
Do not write your code for the exercises in here. Instead, make a copy of the directory containing this file and name your new directory `firstname_surname`. The CMake files contain relative paths so the new directory should be at the same level as the parent `template` directory. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
cmake_minimum_required ( VERSION 2.8.5 ) | ||
|
||
############################################################################### | ||
# Setup | ||
############################################################################### | ||
# Name | ||
project ( WordCounter ) | ||
|
||
# Find custom cmake modules | ||
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../CMake") | ||
|
||
# Common setup | ||
include ( CommonSetup ) | ||
|
||
############################################################################### | ||
# Executable | ||
############################################################################### | ||
|
||
set ( SRC_FILES | ||
src/main.cpp | ||
# add any additional source files here | ||
) | ||
|
||
set ( HDR_FILES | ||
# add any additional header files here | ||
) | ||
|
||
add_executable ( WordCounter ${SRC_FILES} ${HDR_FILES} ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
#include <iostream> | ||
#include <fstream> | ||
#include <sstream> | ||
#include <string> | ||
#include <regex> | ||
#include <unordered_map> | ||
#include <cstring> | ||
#include <iomanip> | ||
|
||
std::string readFile(const std::string &filepath) | ||
{ | ||
std::ifstream inputStream(filepath); | ||
|
||
if (inputStream) | ||
{ | ||
std::ostringstream ss; | ||
ss << inputStream.rdbuf(); | ||
return ss.str(); | ||
} | ||
else | ||
{ | ||
throw std::invalid_argument("Invalid path. Please make sure the file path is correct and the file exists."); | ||
} | ||
} | ||
|
||
std::vector<std::string> tokenizeFile(const std::string &file) | ||
{ | ||
std::regex re("[-\\s]"); | ||
std::sregex_token_iterator first{file.begin(), file.end(), re, -1}, last; | ||
std::vector<std::string> tokens{first, last}; | ||
return tokens; | ||
} | ||
|
||
std::unordered_map<std::string, uint32_t> countWords(const std::vector<std::string> words) | ||
{ | ||
std::unordered_map<std::string, uint32_t> wordsCounts; | ||
for (auto word : words) | ||
{ | ||
std::transform( | ||
word.begin(), word.end(), word.begin(), | ||
[](unsigned char c) | ||
{ return std::tolower(c); }); | ||
word.erase(std::remove_if(word.begin(), word.end(), ispunct), word.end()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The task specifies only needing to consider There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I understood, the comparison should be punctation insensitive. So for example, "what's" should be equal to "whats" but replacing it with whitespace will result in the word not being included (not longer than 4). So in this line, I just remove every punctuation mark. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case I think you may be right |
||
if (word.length() > 4) | ||
{ | ||
wordsCounts[word]++; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you should have a check to see if word is currently in the wordCounts map There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, why is it needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ultimatly it is not required for it to work, but it is better practice to have the check when performing an action on an object in a map where it is not certain that the object will exist. |
||
} | ||
} | ||
return wordsCounts; | ||
} | ||
|
||
void sortAndWriteWords(const std::unordered_map<std::string, uint32_t> &wordsCounts, const std::string &outputDir) | ||
{ | ||
std::vector<std::pair<std::string, int>> wordsCountsPairs; | ||
for (auto &pair : wordsCounts) | ||
{ | ||
wordsCountsPairs.push_back(pair); | ||
} | ||
std::sort( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good sorting process. |
||
wordsCountsPairs.begin(), wordsCountsPairs.end(), | ||
[](auto &left, auto &right) | ||
{ | ||
return left.second > right.second; | ||
}); | ||
|
||
std::ofstream outputFile(outputDir + "\\output.txt"); | ||
|
||
outputFile << std::setw(20) << std::left << "Word" << std::setw(20) << std::left << "Usage" | ||
<< "\n\n"; | ||
|
||
for (auto &it : wordsCountsPairs) | ||
{ | ||
outputFile << std::setw(20) << std::left << it.first << std::setw(20) << std::left << it.second << "\n"; | ||
} | ||
|
||
outputFile.close(); | ||
std::cout << "Found " << wordsCountsPairs.size() << " words and their counts have been successfully written in this path: " << outputDir + "\\output.txt" | ||
<< "\n"; | ||
} | ||
|
||
int main(int, char **) | ||
{ | ||
while (true) | ||
{ | ||
std::cout << "Welcome to the Word Counter program!" | ||
<< "\n\n"; | ||
std::cout << "This program will count the number of occurrences of unique words (longer than 4 characters and split hyphenated words, treating each part as different words)" | ||
<< "\n"; | ||
std::cout << "The count will be case and punctuation insensitive" | ||
<< "\n\n"; | ||
std::cout << "Please enter the path of the file:" | ||
<< "\n"; | ||
std::string inputFilePath; | ||
getline(std::cin, inputFilePath); | ||
|
||
std::string file; | ||
try | ||
{ | ||
file = readFile(inputFilePath); | ||
if (file.empty()) | ||
{ | ||
std::cout << "Note: " | ||
<< "This file is empty so the output will be an empty file." | ||
<< "\n"; | ||
} | ||
} | ||
catch (std::invalid_argument e) | ||
{ | ||
std::cerr << "Error:" << e.what() << "\n\n"; | ||
continue; | ||
} | ||
|
||
std::vector<std::string> tokenizedFile = tokenizeFile(file); | ||
std::unordered_map<std::string, uint32_t> wordsCounts = countWords(tokenizedFile); | ||
|
||
std::string outputFileDir = inputFilePath.substr(0, inputFilePath.rfind('\\')); | ||
sortAndWriteWords(wordsCounts, outputFileDir); | ||
|
||
break; | ||
} | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
cmake_minimum_required ( VERSION 2.8.5 ) | ||
|
||
############################################################################### | ||
# Setup | ||
############################################################################### | ||
# Name | ||
project ( Shapes ) | ||
|
||
# Find custom cmake modules | ||
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../CMake") | ||
|
||
# Common setup | ||
include ( CommonSetup ) | ||
|
||
############################################################################### | ||
# Executable | ||
############################################################################### | ||
|
||
set ( SRC_FILES | ||
src/main.cpp | ||
) | ||
|
||
set ( HDR_FILES | ||
src/Shape.h | ||
src/ShapeSorter.h | ||
) | ||
|
||
add_executable ( Shapes ${SRC_FILES} ${HDR_FILES} ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
|
||
class Shape | ||
{ | ||
public: | ||
virtual std::string getType() = 0; | ||
MohamedAlmaki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
virtual int getSidesCount() = 0; | ||
virtual double getArea() = 0; | ||
virtual double getPerimeter() = 0; | ||
|
||
virtual std::string toString() = 0; | ||
|
||
Shape(int noOfSides) : noOfSides{noOfSides} {} | ||
MohamedAlmaki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
private: | ||
int noOfSides; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this exercise, this could be |
||
}; | ||
|
||
class Square : public Shape | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd have been tempted to have |
||
{ | ||
public: | ||
Square(double side1) : side1{side1}, Shape(2) {} | ||
|
||
std::string getType() | ||
{ | ||
return "Square"; | ||
} | ||
|
||
int getSidesCount() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we have this defined in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that is really bad. Doesn't know why I did it like this. |
||
{ | ||
return 2; | ||
} | ||
|
||
double getArea() | ||
{ | ||
return side1 * side1; | ||
} | ||
|
||
double getPerimeter() | ||
{ | ||
return 4 * side1; | ||
} | ||
|
||
std::string toString() | ||
{ | ||
return "Square(side=" + std::to_string(side1) + ")"; | ||
} | ||
|
||
private: | ||
double side1; | ||
}; | ||
|
||
class Rectangle : public Shape | ||
{ | ||
public: | ||
Rectangle(double side1, double side2) : side1{side1}, side2{side2}, Shape(2) {} | ||
|
||
std::string getType() | ||
{ | ||
return "Rectangle"; | ||
} | ||
|
||
int getSidesCount() | ||
{ | ||
return 2; | ||
} | ||
|
||
double getArea() | ||
{ | ||
return side1 * side2; | ||
} | ||
|
||
double getPerimeter() | ||
{ | ||
return 2 * side1 + 2 * side2; | ||
} | ||
|
||
std::string toString() | ||
{ | ||
return "Rectangle(side1=" + std::to_string(side1) + ", side2=" + std::to_string(side2) + ")"; | ||
} | ||
|
||
private: | ||
double side1, side2; | ||
MohamedAlmaki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
class Circle : public Shape | ||
{ | ||
public: | ||
Circle(double radius) : radius{radius}, Shape(0) {} | ||
|
||
std::string getType() | ||
{ | ||
return "Circle"; | ||
} | ||
|
||
int getSidesCount() | ||
{ | ||
return 0; | ||
} | ||
|
||
double getArea() | ||
{ | ||
return pi * radius * radius; | ||
} | ||
|
||
double getPerimeter() | ||
{ | ||
return 2 * pi * radius; | ||
} | ||
|
||
std::string toString() | ||
{ | ||
return "Circle(radius=" + std::to_string(radius) + ")"; | ||
} | ||
|
||
private: | ||
double radius; | ||
const double pi = 3.14159265358979323846; | ||
MohamedAlmaki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
class Triangle : public Shape | ||
{ | ||
public: | ||
Triangle(double height, double base) : height{height}, base{base}, Shape(3) {} | ||
|
||
std::string getType() | ||
{ | ||
return "Triangle"; | ||
} | ||
|
||
int getSidesCount() | ||
{ | ||
return 3; | ||
} | ||
|
||
double getArea() | ||
{ | ||
return 0.5 * height * base; | ||
} | ||
|
||
double getPerimeter() | ||
{ | ||
return base + 2 * std::sqrt(height * height + (base * base) / 4); | ||
} | ||
|
||
std::string toString() | ||
{ | ||
return "Triangle(height=" + std::to_string(height) + ", base=" + std::to_string(base) + ")"; | ||
} | ||
|
||
private: | ||
double height, base; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the inent of this that the experssion match a hyphen of a whitespace, but a double backslash exits the special character.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex is used to split the string by two delimiters, the space, and the hyphen. It will match a space or a hyphen. After that, the expression is used in a reverse way, to get all the words that don't match it i.e. the split words.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Hyphen is also a special character and will need to be exited as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it will be removed. For example, the string "lines are hard-coded" will be transformed into a vector of ["lines", "are", "hard", "coded"] by this expression.