From 38c1a8e0d9d2e20a589f4d1e32c1ac26cce0646f Mon Sep 17 00:00:00 2001 From: JamesFlare1212 Date: Thu, 13 Feb 2025 14:25:13 -0500 Subject: [PATCH] add solution of HW4 --- .vscode/launch.json | 18 ++++ .vscode/settings.json | 22 ++++- hws/yelp_businesses/Business.cpp | 127 ++++++++++++++++++++++++++ hws/yelp_businesses/Business.h | 31 +++++++ hws/yelp_businesses/README.txt | 14 ++- hws/yelp_businesses/nybusninesses.cpp | 93 +++++++++++++++++++ 6 files changed, 300 insertions(+), 5 deletions(-) create mode 100644 hws/yelp_businesses/Business.cpp create mode 100644 hws/yelp_businesses/Business.h create mode 100644 hws/yelp_businesses/nybusninesses.cpp diff --git a/.vscode/launch.json b/.vscode/launch.json index 21292a0..f5d9fc7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -52,6 +52,24 @@ "MIMode": "gdb", "miDebuggerPath": "/usr/bin/gdb", "preLaunchTask": "C/C++: g++ build active file" + }, + { + "name": "nybusninesses", + "type": "cppdbg", + "request": "launch", + "program": "${fileDirname}/${fileBasenameNoExtension}", + "args": [ + "large_input1.json", + "output.txt", + "93101", + "Shopping", + "debug" + ], + "cwd": "${fileDirname}", + "environment": [], + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb", + "preLaunchTask": "C/C++: g++ build active file" } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 5c12af3..7a29424 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -51,6 +51,26 @@ "stdexcept": "cpp", "streambuf": "cpp", "typeinfo": "cpp", - "cassert": "cpp" + "cassert": "cpp", + "bitset": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "condition_variable": "cpp", + "cstring": "cpp", + "ratio": "cpp", + "mutex": "cpp", + "semaphore": "cpp", + "span": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "variant": "cpp", + "format": "cpp", + "__nullptr": "cpp", + "__bit_reference": "cpp", + "__hash_table": "cpp", + "__string": "cpp", + "queue": "cpp", + "stack": "cpp" } } \ No newline at end of file diff --git a/hws/yelp_businesses/Business.cpp b/hws/yelp_businesses/Business.cpp new file mode 100644 index 0000000..c221c8e --- /dev/null +++ b/hws/yelp_businesses/Business.cpp @@ -0,0 +1,127 @@ +#include +#include +#include + +#include "Business.h" + +//extracts a string value for the given field +std::string extractJsonString(const std::string &line, const std::string &field) { + std::string pattern = "\"" + field + "\":"; + size_t pos = line.find(pattern); + if (pos == std::string::npos) {return "";} //in case pattern not found + pos += pattern.length(); + //skip any whitespace + while (pos < line.size() && isspace(line[pos])) {pos++;} + if (pos >= line.size() || line[pos] != '\"') {return "";} //in case the opening quote is not found + pos++; + //skip the opening quote + size_t endPos = line.find("\"", pos); + if (endPos == std::string::npos) {return "";} //in case the closing quote is not found + return line.substr(pos, endPos - pos); +} + +//extracts an integer value for the given field +int extractJsonInt(const std::string &line, const std::string &field) { + std::string pattern = "\"" + field + "\":"; + size_t pos = line.find(pattern); + if (pos == std::string::npos) {return -1;} //in case the pattern is not found + pos += pattern.length(); + //skip any whitespace + while (pos < line.size() && isspace(line[pos])) {pos++;} + size_t endPos = pos; + //skip the negative sign + if (line[endPos] == '-') {endPos++;} + //skip the digits + while (endPos < line.size() && isdigit(line[endPos])) {endPos++;} + std::string numStr = line.substr(pos, endPos - pos); + int value = std::stoi(numStr); + if (value == 0) {return -1;} //in case the number is not found + return value; +} + +//extracts a double value for the given field +double extractJsonDouble(const std::string &line, const std::string &field) { + std::string pattern = "\"" + field + "\":"; + size_t pos = line.find(pattern); + if (pos == std::string::npos) {return 0.0;} // in case the pattern is not found + pos += pattern.length(); + //skip any whitespace + while (pos < line.size() && isspace(line[pos])) {pos++;} + if (line[pos] == '\"') { + //in case the data is quoted + pos++; + size_t endPos = line.find("\"", pos); + if (endPos == std::string::npos) {return 0.0;} + std::string numStr = line.substr(pos, endPos - pos); + double value = std::stod(numStr); + if (value == 0.0) {return 0.0;} //in case the number is not found + return value; + } else { + //in case the data is not quoted + size_t endPos = pos; + while (endPos < line.size() && (isdigit(line[endPos]) || line[endPos] == '.' || line[endPos]=='-')) { + endPos++; + } + std::string numStr = line.substr(pos, endPos - pos); + double value = std::stod(numStr); + if (value == 0.0) {return 0.0;} //in case the number is not found + return value; + } +} + +//extracts a price value for the given field +int extractJsonPrice(const std::string &line, const std::string &field) { + std::string pattern = "\"" + field + "\":"; + size_t pos = line.find(pattern); + if (pos == std::string::npos) {return -1;} //in case the pattern is not found + pos += pattern.length(); + //skip any whitespace + while (pos < line.size() && isspace(line[pos])) {pos++;} + if (line[pos] == '\"') { + pos++; + size_t endPos = line.find("\"", pos); + if (endPos == std::string::npos) {return -1;} + std::string numStr = line.substr(pos, endPos - pos); + if (numStr == "None") {return -1;} //in case the number is not found + return std::stoi(numStr); + } else { + size_t endPos = pos; + while (endPos < line.size() && (isdigit(line[endPos]) || line[endPos]=='-')) { + endPos++; + } + std::string numStr = line.substr(pos, endPos - pos); + if (numStr == "None") {return -1;} //in case the number is not found + return std::stoi(numStr); + } +} + +//load the business data from a JSON line +Business::Business(const std::string &jsonLine) { + name = extractJsonString(jsonLine, "name"); + categories = extractJsonString(jsonLine, "categories"); + rating = extractJsonDouble(jsonLine, "stars"); + price = extractJsonPrice(jsonLine, "RestaurantsPriceRange2"); + review_count = extractJsonInt(jsonLine, "review_count"); + city = extractJsonString(jsonLine, "city"); + postal_code = extractJsonString(jsonLine, "postal_code"); +} + +std::string Business::getName() const {return name;} +std::string Business::getCategories() const {return categories;} +double Business::getRating() const {return rating;} +int Business::getPrice() const {return price;} +int Business::getReviewCount() const {return review_count;} +std::string Business::getCity() const {return city;} +std::string Business::getPostalCode() const {return postal_code;} + +//returns a string representing the star rating. +std::string Business::getStarString() const { + int fullStars = static_cast(rating); + double fraction = rating - fullStars; + std::string stars; + for (int i = 0; i < fullStars; ++i) + stars += "\u2605"; + if (fraction >= 0.5) + stars += "\u00BD"; + return stars; +} diff --git a/hws/yelp_businesses/Business.h b/hws/yelp_businesses/Business.h new file mode 100644 index 0000000..291b4a2 --- /dev/null +++ b/hws/yelp_businesses/Business.h @@ -0,0 +1,31 @@ +#ifndef BUSINESS_H +#define BUSINESS_H + +#include + +class Business { +public: + //constructs a Business by parsing a JSON-formatted line + Business(const std::string &jsonLine); + //Accessors + std::string getName() const; + std::string getCategories() const; + double getRating() const; + int getPrice() const; + int getReviewCount() const; + std::string getCity() const; + std::string getPostalCode() const; + //returns a string representation of the star rating + std::string getStarString() const; + +private: + std::string name; + std::string categories; + double rating; + int price; + int review_count; + std::string city; + std::string postal_code; +}; + +#endif // BUSINESS_H diff --git a/hws/yelp_businesses/README.txt b/hws/yelp_businesses/README.txt index fefc0ad..490eec6 100644 --- a/hws/yelp_businesses/README.txt +++ b/hws/yelp_businesses/README.txt @@ -1,7 +1,7 @@ HOMEWORK 4: Yelp Businesses -NAME: < insert name > +NAME: Jinshan Zhou COLLABORATORS AND OTHER RESOURCES: @@ -10,13 +10,14 @@ List the names of everyone you talked to about this assignment LMS, etc.), and all of the resources (books, online reference material, etc.) you consulted in completing this assignment. -< insert collaborators / resources > +Not really, but when I handle the list, I check many lab examples. Also, I check the +sstream example from alb and my previous homework as well. Remember: Your implementation for this assignment must be done on your own, as described in "Academic Integrity for Homework" handout. -ESTIMATE OF # OF HOURS SPENT ON THIS ASSIGNMENT: < insert # hours > +ESTIMATE OF # OF HOURS SPENT ON THIS ASSIGNMENT: 13 MISC. COMMENTS TO GRADER: @@ -33,4 +34,9 @@ What parts of the assignment did you find challenging? Is there anything that finally "clicked" for you in the process of working on this assignment? How well did the development and testing process go for you? -< insert reflection > +I just start writing the code and implementation directly. Then, I found there are +a few given codes on the end instruction. But, it's too late for me. I didn't fully +read through the instruction at the beginning. Which brings me some extra work. +When I realize that, other parts of my code already depends on my extract JSON functions. +So, I have to keep writing on top of that. If, I can do this again, I will check the +instruction in detail and find if there are useful cases. diff --git a/hws/yelp_businesses/nybusninesses.cpp b/hws/yelp_businesses/nybusninesses.cpp new file mode 100644 index 0000000..082815e --- /dev/null +++ b/hws/yelp_businesses/nybusninesses.cpp @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + +#include "Business.h" + +int main(int argc, char* argv[]) { + if (argc < 5) { + std::cerr << "Usage: " << argv[0] + << " input.json output.txt zipcode [categories...]" + << std::endl; + return 1; + } + //load the arguments + std::string inputFile = argv[1]; + std::string outputFile = argv[2]; + std::string zipcode = argv[3]; + //read all categories from arguments + std::vector searchCategories; + for (int i = 4; i < argc; ++i) { + searchCategories.push_back(argv[i]); + } + //open the input file + std::ifstream inFile(inputFile.c_str()); + if (!inFile) { + std::cerr << "Error: Could not open input file: " + << inputFile << std::endl; + return 1; + } + //open the output file + std::ofstream outFile(outputFile.c_str()); + if (!outFile) { + std::cerr << "Error: Could not open output file: " + << outputFile << std::endl; + return 1; + } + //read each line and create a Business object if it matches the zipcode and at least one search category + std::list matchingBusinesses; + std::string line; + while (std::getline(inFile, line)) { + Business biz(line); + //check zipcode + if (biz.getPostalCode() != zipcode) + continue; + //check categories: at least one category must be found + bool categoryMatch = false; + std::string bizCategories = biz.getCategories(); + for (std::vector::const_iterator catIt = searchCategories.begin(); + catIt != searchCategories.end(); ++catIt) { + if (bizCategories.find(*catIt) != std::string::npos) { + categoryMatch = true; + break; + } + } + if (categoryMatch) { + matchingBusinesses.push_back(biz); + } + } + //sort the list by rating in descending order + matchingBusinesses.sort([](const Business &a, const Business &b) { + return a.getRating() > b.getRating(); + }); + //output the results in a format similar to Yelp. + if (matchingBusinesses.empty()) { + outFile << "Sorry, we couldn't find any results" << std::endl; + } else { + int index = 1; + for (std::list::const_iterator it = matchingBusinesses.begin(); + it != matchingBusinesses.end(); ++it) { + outFile << "=====================" << std::endl; + //add line 1: Index and Business Name + outFile << index << ". " << it->getName() << std::endl; + //add line 2: Star rating, numeric rating, and review count + outFile << it->getStarString() << " " << it->getRating() + << " (" << it->getReviewCount() << " reviews)" << std::endl; + //add line 3: City and then the price range (if available) + outFile << it->getCity() << " "; + if (it->getPrice() != -1) { + for (int i = 0; i < it->getPrice(); ++i) + outFile << "$"; + } + outFile << std::endl; + //add line 4: Categories + outFile << it->getCategories() << std::endl; + index++; + } + outFile << "=====================" << std::endl; + } + return 0; +}