From 59315f94453991068dec9234280ccdc6971aeb55 Mon Sep 17 00:00:00 2001 From: leca Date: Sat, 22 Mar 2025 01:02:37 +0300 Subject: [PATCH] net weights implementation WIP --- CMakeLists.txt | 12 ++------ goods/goods.cpp | 12 ++++---- goods/goods.h | 5 +++- outputdialog.cpp | 3 +- parser/module.cpp | 63 +++++++++++++++++++----------------------- parser/module.h | 6 ++++ parser/parser.cpp | 45 ++++++++---------------------- solvecaptchadialog.cpp | 1 - translations/en_US.ts | 4 +-- translations/ru_RU.ts | 4 +-- utils/utils.cpp | 38 +++++++++++++++++++++---- utils/utils.h | 5 ++++ 12 files changed, 104 insertions(+), 94 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6eb4f46..2644512 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,15 +216,9 @@ endif() target_link_libraries(checks-parser PRIVATE -lcurl) -find_package(Boost 1.45.0 COMPONENTS boost_regex) - -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - target_link_libraries(checks-parser PUBLIC ${Boost_LIBRARIES}) -else() - message(FATAL_ERROR "No BOOST library found. Please, install one. If you beleive this is an error, please, contact the developer.") - return() -endif() +find_package(Boost 1.45.0 CONFIG REQUIRED COMPONENTS regex) +include_directories(${Boost_INCLUDE_DIRS}) +target_link_libraries(checks-parser PUBLIC ${Boost_LIBRARIES}) if (BUILD_OCR_MODE OR BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN) find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs) diff --git a/goods/goods.cpp b/goods/goods.cpp index b41578f..8857749 100644 --- a/goods/goods.cpp +++ b/goods/goods.cpp @@ -1,11 +1,9 @@ #include "goods.h" #include -Goods::Goods(std::string name, double price_per_unit, double quantity) { - this->name = name; - this->price_per_unit = price_per_unit; - this->quantity = quantity; -} +Goods::Goods(std::string name, double price_per_unit, std::string net_weight, double quantity) : + name(name), price_per_unit(price_per_unit), + net_weight(net_weight), quantity(quantity) {} double Goods::calculate_total_price() { return this->price_per_unit * this->quantity; @@ -15,12 +13,16 @@ std::string Goods::get_name() { return this->name; } double Goods::get_quantity() { return this->quantity; } +std::string Goods::get_net_weight() { return this->net_weight; } + double Goods::get_price_per_unit() { return this->price_per_unit; } void Goods::set_name(std::string name) { this->name = name; } void Goods::set_quantity(double quantity) { this->quantity = quantity; } +void Goods::set_net_weight(std::string net_weight) { this->net_weight = net_weight; } + void Goods::set_price_per_unit(double price_per_unit) { this->price_per_unit = price_per_unit; } diff --git a/goods/goods.h b/goods/goods.h index dee5b70..ccbe3e3 100644 --- a/goods/goods.h +++ b/goods/goods.h @@ -7,17 +7,20 @@ class Goods { std::string name; double quantity; // by weight or by the piece + std::string net_weight; // will contain values like "5мл" or "10г" double price_per_unit; public: - Goods(std::string, double, double); + Goods(std::string name, double quantity, std::string net_weight, double price_per_unit); double calculate_total_price(); std::string get_name(); double get_quantity(); + std::string get_net_weight(); double get_price_per_unit(); void set_name(std::string); void set_quantity(double); + void set_net_weight(std::string); void set_price_per_unit(double); }; diff --git a/outputdialog.cpp b/outputdialog.cpp index 7c7891e..23bc4a9 100644 --- a/outputdialog.cpp +++ b/outputdialog.cpp @@ -83,8 +83,7 @@ void OutputDialog::on_buttonBox_accepted() { output_file << std::fixed << std::setprecision(2) << goods.get_quantity(); break; case ColumnType::goods_net_weight: - output_file << "TODO"; - // TODO + output_file << goods.get_net_weight(); break; case ColumnType::goods_total: output_file << std::fixed << std::setprecision(2) << goods.calculate_total_price(); diff --git a/parser/module.cpp b/parser/module.cpp index 7c4ba5d..8677f5c 100644 --- a/parser/module.cpp +++ b/parser/module.cpp @@ -1,11 +1,25 @@ #include "module.h" + #include #include #include -#include "../utils/utils.h" +#include #include + StoreModule::StoreModule() {} +std::vector StoreModule::parse(std::wstring str, std::wstring regexp, boost::regex_constants::flag_type_ flag) { + std::vector result; + boost::wregex r(regexp, flag); + + for (boost::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end; + it++) { + result.push_back(to_utf8(it->str())); + } + + return result; +} + StoreModule::StoreModule(std::string path) { std::ifstream settings_file(path); nlohmann::json settings = nlohmann::json::parse(settings_file); @@ -13,54 +27,35 @@ StoreModule::StoreModule(std::string path) { this->name = from_utf8(settings["name"]); this->goods_name_regex = from_utf8(settings["goods_name_regex"]); this->goods_price_regex = from_utf8(settings["goods_price_regex"]); + this->goods_net_weight_regex = from_utf8(settings["goods_net_weight_regex"]); this->goods_quantity_regex = from_utf8(settings["goods_quantity_regex"]); this->check_start_regex = from_utf8(settings["check_start_regex"]); this->check_end_regex = from_utf8(settings["check_end_regex"]); - -#ifdef DEBUG - std::wcout << "Name: " << this->name << std::endl; - std::wcout << "Goods name regex: " << this->goods_name_regex << std::endl; - std::wcout << "Goods price regex: " << this->goods_price_regex << std::endl; - std::wcout << "Goods quantity regex: " << this->goods_quantity_regex - << std::endl; - std::wcout << "Check start regex: " << this->check_start_regex << std::endl; - std::wcout << "Check end regex: " << this->check_end_regex << std::endl; -#endif } std::vector StoreModule::parse_name(std::wstring str) { - std::vector result; - boost::wregex r(this->goods_name_regex, boost::regex_constants::extended); - - for (boost::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end; - it++) { - result.push_back(to_utf8(it->str())); - } - - return result; + return parse(str, this->goods_name_regex, boost::regex_constants::extended); } std::vector StoreModule::parse_price(std::wstring str) { + return parse(str, this->goods_price_regex, boost::regex_constants::collate); +} + +std::vector StoreModule::parse_net_weight(std::vector &names) { std::vector result; - boost::wregex r(this->goods_price_regex, boost::regex::collate); - - for (boost::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end; - it++) { - result.push_back(to_utf8(it->str())); + for (std::string &name : names) { + std::vector parsed = parse(from_utf8(name), this->goods_net_weight_regex, boost::regex_constants::collate); + if (parsed.size() == 0) { + result.push_back("?"); + } else { + result.push_back(parsed[0]); + } } - return result; } std::vector StoreModule::parse_quantity(std::wstring str) { - std::vector result; - boost::wregex r(this->goods_quantity_regex, boost::regex::collate); - - for (boost::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end; - it++) { - result.push_back(to_utf8(it->str())); - } - return result; + return parse(str, this->goods_quantity_regex, boost::regex_constants::collate); } std::wstring StoreModule::trim_check(std::wstring& check) { diff --git a/parser/module.h b/parser/module.h index 664cc66..09c7efe 100644 --- a/parser/module.h +++ b/parser/module.h @@ -3,22 +3,28 @@ #include #include +#include class StoreModule { std::string path; std::wstring name; std::wstring goods_name_regex; std::wstring goods_price_regex; + std::wstring goods_net_weight_regex; std::wstring goods_quantity_regex; std::wstring check_start_regex; std::wstring check_end_regex; + + std::vector parse(std::wstring, std::wstring, boost::regex_constants::flag_type_); public: StoreModule(std::string); StoreModule(); std::vector parse_name(std::wstring); std::vector parse_price(std::wstring); + std::vector parse_net_weight(std::vector &names); std::vector parse_quantity(std::wstring); + std::wstring trim_check(std::wstring&); diff --git a/parser/parser.cpp b/parser/parser.cpp index daf6743..bd44543 100644 --- a/parser/parser.cpp +++ b/parser/parser.cpp @@ -1,8 +1,9 @@ #include "parser.h" -#include "../goods/goods.h" -#include "../net/net.h" -#include "../settings/settings.h" -#include "../utils/utils.h" + +#include +#include +#include +#include #include #include @@ -15,27 +16,6 @@ using namespace std::filesystem; #endif -static void dumpVectorsToStdErr(std::vector &goods_names, std::vector &goods_prices, std::vector& goods_quantities) { - std::cerr << goods_names.size() << " " << goods_prices.size() << " " << goods_quantities.size() << std::endl; - std::cerr << "Found goods names: "; - for (auto &goods_name : goods_names) { - std::cerr << goods_name << " "; - } - std::cerr << std::endl; - - std::cerr << "Found goods prices: "; - for (auto &goods_price : goods_prices) { - std::cerr << goods_price << " "; - } - std::cerr << std::endl; - - std::cerr << "Found goods names: "; - for (auto &goods_quantity : goods_quantities) { - std::cerr << goods_quantity << " "; - } - std::cerr << std::endl; -} - Parser::Parser() {} std::vector Parser::search_modules() { @@ -84,22 +64,21 @@ std::vector Parser::parse(std::wstring check_plaintext) { std::vector goods_names = module.parse_name(check_plaintext); std::vector goods_prices = module.parse_price(check_plaintext); - std::vector goods_quantities = - module.parse_quantity(check_plaintext); + std::vector goods_net_weights = module.parse_net_weight(goods_names); + std::vector goods_quantities = module.parse_quantity(check_plaintext); - if (goods_names.size() != goods_prices.size() || - goods_names.size() != goods_quantities.size() || - goods_prices.size() != goods_quantities.size()) { - // dumpVectorsToStdErr(goods_names, goods_prices, goods_quantities); + if (areAllSizesEqual(goods_names, goods_prices, goods_net_weights, goods_quantities)) { - //Error. Amount of names, prices or quantities are not equal. That means, that some regex(es) has mismatched. + // dumpVectorsToStderr(goods_names, goods_prices, goods_net_weights, goods_quantities); + + //Error. Amount of names, prices, net weights or quantities are not equal. That means, that some regex(es) has mismatched. return {}; } short goods_amount = goods_names.size(); for (short i = 0; i < goods_amount; i++) { - Goods goods(goods_names[i], std::stof(goods_prices[i]), std::stof(goods_quantities[i])); + Goods goods(goods_names[i], std::stod(goods_prices[i]), goods_net_weights[i], std::stod(goods_quantities[i])); result.push_back(goods); } diff --git a/solvecaptchadialog.cpp b/solvecaptchadialog.cpp index 8343d5d..d67d2e3 100644 --- a/solvecaptchadialog.cpp +++ b/solvecaptchadialog.cpp @@ -11,7 +11,6 @@ SolveCaptchaDialog::SolveCaptchaDialog(QWidget *parent, std::string* solved_capt ui->setupUi(this); QString captcha_path = QString::fromStdString(get_path_relative_to_home(".local/share/checks_parser/captcha.jpg")); - std::cout << captcha_path.toStdString() << std::endl; ui->captcha_picture->setPixmap(captcha_path); ui->captcha_picture->setScaledContents(true); } diff --git a/translations/en_US.ts b/translations/en_US.ts index 08f5682..4e51be1 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -573,12 +573,12 @@ Dialog - + Please, enter a valid captcha Please, enter a valid captcha - + No captcha No captcha diff --git a/translations/ru_RU.ts b/translations/ru_RU.ts index a600396..1eebc78 100644 --- a/translations/ru_RU.ts +++ b/translations/ru_RU.ts @@ -573,12 +573,12 @@ Диалог - + Please, enter a valid captcha Пожалуйста, введите верную капчу - + No captcha Нет капчи diff --git a/utils/utils.cpp b/utils/utils.cpp index f274d58..af35aaa 100644 --- a/utils/utils.cpp +++ b/utils/utils.cpp @@ -73,10 +73,17 @@ bool vector_contains_element(const std::vector& vector, const T& to_find) { } return false; } +template +bool areAllSizesEqual(const std::vector& v1, const std::vector& v2, + const std::vector& v3, const std::vector& v4) { + return (v1.size() == v2.size() && v2.size() == v3.size() && v3.size() == v4.size()); +} + //ужас template bool vector_contains_element(const std::vector& vector, const std::string& to_find); - +template bool areAllSizesEqual(const std::vector& v1, const std::vector& v2, + const std::vector& v3, const std::vector& v4); std::vector split(std::string s, std::string delimiter) { std::vector result; size_t pos = 0; @@ -147,7 +154,7 @@ std::vector find_in_html(std::string& html, std::string regex, std } std::vector find_products_in_html(std::string html) { - return find_in_html(html, "
.*<\\/b><\\/div>", "
", "<\\/b><\\/div>"); + return find_in_html(html, "
.{10,100}<\\/b><\\/div>", "
", "<\\/b><\\/div>"); } std::vector find_amounts_in_html(std::string html) { @@ -159,6 +166,19 @@ std::vector find_amounts_in_html(std::string html) { return founds; } +std::vector find_net_weights_in_names(std::vector &names) { + std::vector result; + for (std::wstring &name : names ) { + boost::wregex regexp(from_utf8("((\\d+(.|,)?\\d?((м|)л|(к|м|)г|т|ц|шт|(pc|)s|(m|k|)g|(m|)l|t)).?)+"), boost::regex_constants::collate); + for (boost::wsregex_iterator it{name.begin(), name.end(), regexp}, end{}; it != end; + it++) { + result.push_back(it->str()); + break; + } + } + return result; +} + std::vector find_prices_in_html(std::string html) { std::vector founds = find_in_html(html, "X <\\/span>\\d+(\\.|,)\\d{2}<\\/span>", "X <\\/span>", "<\\/span>"); for (auto &found : founds) { @@ -168,7 +188,7 @@ std::vector find_prices_in_html(std::string html) { return founds; } -void dumpVectorsToStderr(std::vector &products, std::vector &amounts, std::vector &prices) { +void dumpVectorsToStderr(std::vector &products, std::vector &amounts, std::vector &net_weights, std::vector &prices) { std::cerr << "Products: "; for (auto &product : products) { std::cerr << to_utf8(product) << "|[]|"; @@ -181,6 +201,12 @@ void dumpVectorsToStderr(std::vector &products, std::vector products = find_products_in_html(trimmed); std::vector amounts = find_amounts_in_html(trimmed); + std::vector net_weights = find_net_weights_in_names(products); std::vector prices = find_prices_in_html(trimmed); if ((products.size() + amounts.size() + prices.size()) == 0) { @@ -209,7 +236,7 @@ Check parseOfdRuAnswer(std::string html) { } if ((products.size() + amounts.size() + prices.size())/products.size() != 3) { - dumpVectorsToStderr(products, amounts, prices); + dumpVectorsToStderr(products, amounts, net_weights, prices); //TOOD: make new setting "app_home" and get all path using it. std::ofstream error_log(get_path_relative_to_home(".local/share/checks_parser/error_log.txt"), std::ios_base::app); error_log << trimmed << std::endl; @@ -220,7 +247,7 @@ Check parseOfdRuAnswer(std::string html) { Check c; for (int i = 0; i < products.size(); i ++) { - Goods goods(to_utf8(products[i]), std::stod(prices[i]), std::stod(amounts[i])); + Goods goods(to_utf8(products[i]), std::stod(prices[i]), to_utf8(net_weights[i]), std::stod(amounts[i])); c.add_goods(goods); } @@ -254,3 +281,4 @@ void generate_qr_code(std::string data) { QRcode_free(qrCode); } #endif // ifdef BUILD_OFD_BINARYEYE_SCAN + diff --git a/utils/utils.h b/utils/utils.h index 36019e8..3cba741 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -12,6 +12,9 @@ std::string get_path_relative_to_home(std::string path); template bool vector_contains_element(const std::vector &vector, const T &to_find); +template +bool areAllSizesEqual(const std::vector& v1, const std::vector& v2, + const std::vector& v3, const std::vector& v4); std::vector split(std::string, std::string); @@ -26,4 +29,6 @@ void generate_qr_code(std::string data); std::string get_local_ip_address(); #endif + + #endif // UTILS_H