diff --git a/src/src/util/kv.cpp b/src/src/util/kv.cpp index 84ee6c9..dea51ed 100644 --- a/src/src/util/kv.cpp +++ b/src/src/util/kv.cpp @@ -1,81 +1,81 @@ -#include "easypr/util/kv.h" -#include "easypr/util/util.h" +#include "easypr/util/kv.h" // 引入kv头文件 +#include "easypr/util/util.h" // 引入util头文件 -namespace easypr { +namespace easypr { // 定义easypr命名空间 -Kv::Kv() { } +Kv::Kv() { } // Kv类构造函数 -void Kv::load(const std::string &file) { - this->clear(); - std::ifstream reader(file); - assert(reader); +void Kv::load(const std::string &file) { // 加载文件 + this->clear(); // 清空数据 + std::ifstream reader(file); // 创建文件读取流 + assert(reader); // 断言文件读取流创建成功 - if (reader.is_open()) { - while (!reader.eof()) { - std::string line; - std::getline(reader, line); - if (line.empty()) continue; + if (reader.is_open()) { // 如果文件打开成功 + while (!reader.eof()) { // 当未到达文件末尾时 + std::string line; // 定义字符串变量line + std::getline(reader, line); // 读取一行数据到line + if (line.empty()) continue; // 如果line为空,则跳过本次循环 - const auto parse = [](const std::string &str) { - std::string tmp, key, value; - for (size_t i = 0, len = str.length(); i < len; ++i) { - const char ch = str[i]; - if (ch == ' ') { - if (i > 0 && str[i - 1] != ' ' && key.empty()) { - key = tmp; - tmp.clear(); + const auto parse = [](const std::string &str) { // 定义解析函数 + std::string tmp, key, value; // 定义临时变量、键、值 + for (size_t i = 0, len = str.length(); i < len; ++i) { // 遍历字符串 + const char ch = str[i]; // 获取当前字符 + if (ch == ' ') { // 如果当前字符为空格 + if (i > 0 && str[i - 1] != ' ' && key.empty()) { // 如果前一个字符不为空格且键为空 + key = tmp; // 将临时变量赋值给键 + tmp.clear(); // 清空临时变量 } } else { - tmp.push_back(ch); + tmp.push_back(ch); // 将当前字符添加到临时变量 } - if (i == len - 1) { - value = tmp; + if (i == len - 1) { // 如果当前字符是最后一个字符 + value = tmp; // 将临时变量赋值给值 } } - return std::make_pair(key, value); + return std::make_pair(key, value); // 返回键值对 }; - auto kv = parse(line); - this->add(kv.first, kv.second); + auto kv = parse(line); // 解析行数据 + this->add(kv.first, kv.second); // 添加键值对 } - reader.close(); + reader.close(); // 关闭文件读取流 } } -std::string Kv::get(const std::string &key) { - if (data_.find(key) == data_.end()) { - std::cerr << "[Kv] cannot find " << key << std::endl; - return ""; +std::string Kv::get(const std::string &key) { // 获取键对应的值 + if (data_.find(key) == data_.end()) { // 如果键不存在 + std::cerr << "[Kv] cannot find " << key << std::endl; // 输出错误信息 + return ""; // 返回空字符串 } - return data_.at(key); + return data_.at(key); // 返回键对应的值 } -void Kv::add(const std::string &key, const std::string &value) { - if (data_.find(key) != data_.end()) { +void Kv::add(const std::string &key, const std::string &value) { // 添加键值对 + if (data_.find(key) != data_.end()) { // 如果键已存在 fprintf(stderr, "[Kv] find duplicate: %s = %s , ignore\n", key.c_str(), - value.c_str()); + value.c_str()); // 输出错误信息 } else { std::string v(value); #ifdef OS_WINDOWS - v = utils::utf8_to_gbk(value.c_str()); + v = utils::utf8_to_gbk(value.c_str());()); // 如果是Windows系统,将值转换为gbk编码 #endif - data_[key] = v; + data_[key] = v; // 添加键值对 } } -void Kv::remove(const std::string &key) { - if (data_.find(key) == data_.end()) { - std::cerr << "[Kv] cannot find " << key << std::endl; - return; +void Kv::remove(const std::string &key) { // 删除键值对 + if (data_.find(key) == data_.end()) { // 如果键不存在 + std::cerr << "[Kv] cannot find " << key << std::endl; // 输出错误信息 + return; // 返回 } - data_.erase(key); + data_.erase(key); // 删除键值对 } -void Kv::clear() { - data_.clear(); +void Kv::clear() { // 清空数据 + data_.clear(); // 清空数据 } } diff --git a/src/src/util/program_options.cpp b/src/src/util/program_options.cpp index a1b7c8d..4b07eb3 100644 --- a/src/src/util/program_options.cpp +++ b/src/src/util/program_options.cpp @@ -3,423 +3,429 @@ namespace program_options { // class ParseError - -ParseError::ParseError(const std::string& msg) : _msg(msg) {} - -const char* ParseError::what() const throw() { - std::string msg; - msg.append("Command line parse error: ").append(_msg).push_back('.'); - return msg.c_str(); +//定义了一个名为ParseError的类 +//ParseError类是一个用于处理命令行解析错误的异常类。 +ParseError::ParseError(const std::string& msg) : _msg(msg) {}//是ParseError类的构造函数 +//它接受一个字符串作为参数,并将这个字符串赋值给成员变量_msg。 +const char* ParseError::what() const throw() {//是一个成员函数,它返回一个描述错误的字符串 + std::string msg;//首先创建一个新的字符串 + msg.append("Command line parse error: ").append(_msg).push_back('.');//添加一个错误消息前缀,接着添加成员变量_msg,最后添加一个句点。 + return msg.c_str();//返回这个字符串的C风格字符串。 } -ParseError::~ParseError() throw() {} +ParseError::~ParseError() throw() {}// 是ParseError类的析构函数 // class Generator - -Generator::Generator() : parser_(nullptr) { - current_subroutine_ = Subroutine::get_default_name(); - add_subroutine(current_subroutine_.c_str()); +//定义了一个名为Generator的类,该类用于生成和管理命令行选项解析器和子程序。 +Generator::Generator() : parser_(nullptr) {//Generator类的构造函数 + current_subroutine_ = Subroutine::get_default_name();//初始化parser_为nullptr,设置当前子程序为默认子程序 + add_subroutine(current_subroutine_.c_str());//添加这个子程序。 } -Generator::~Generator() { +Generator::~Generator() {//Generator类的析构函数 if (parser_) { delete parser_; parser_ = nullptr; - } + }//它删除parser_和所有的子程序 for (auto it = subroutines_.begin(); it != subroutines_.end(); ++it) { if (it->second) { - delete it->second; - it->second = nullptr; + delete it->second;//它删除所有的子程序, + it->second = nullptr;//并将parser_和所有的子程序设置为nullptr。 } } } -Generator& Generator::make_usage(const char* first_line) { - get_subroutine()->set_first_line(first_line); - return *this; +Generator& Generator::make_usage(const char* first_line) {//是一个成员函数 + get_subroutine()->set_first_line(first_line);//它设置当前子程序的第一行 + return *this;//并返回this指针。 } -Parser* Generator::make_parser() { +Parser* Generator::make_parser() {//是一个成员函数 if (parser_) delete parser_; - parser_ = new Parser; - parser_->set_usage_subroutines(&subroutines_); - return parser_; + parser_ = new Parser;//它创建一个新的Parser对象 + parser_->set_usage_subroutines(&subroutines_);//设置其使用的子程序 + return parser_;//并返回这个Parser对象。 } -Generator& Generator::add_subroutine(const char* name) { - add_subroutine(name, ""); +Generator& Generator::add_subroutine(const char* name) {//是成员函数 + add_subroutine(name, "");//它们添加一个新的子程序。 return *this; } Generator& Generator::add_subroutine(const char* name, - const char* description) { - if (subroutines_.find(name) == subroutines_.end()) { + const char* description) {//成员函数 + if (subroutines_.find(name) == subroutines_.end()) {//如果子程序已经存在,它们不会添加。 // a new subroutine - current_subroutine_ = name; - Subroutine* routine = new Subroutine(name, description); - subroutines_.insert({current_subroutine_, routine}); + current_subroutine_ = name;//设立新名字 + Subroutine* routine = new Subroutine(name, description);//新建一个子程序。 + subroutines_.insert({current_subroutine_, routine});//添加一个新的子程序。 } return *this; } -std::map Generator::get_subroutine_list() { +std::map Generator::get_subroutine_list() {//是一个成员函数,它返回一个包含所有子程序名称和描述的映射。 std::map kv; - for (auto pr : subroutines_) { - Subroutine* subroutine = pr.second; - if (subroutine->get_name() != Subroutine::get_default_name()) - kv[subroutine->get_name()] = subroutine->get_description(); + for (auto pr : subroutines_) {//遍历所有的子程序 + Subroutine* subroutine = pr.second;//遍历所有的子程序 + if (subroutine->get_name() != Subroutine::get_default_name())//如果子程序的名称不是默认名称 + kv[subroutine->get_name()] = subroutine->get_description();//将子程序的名称和描述添加到映射中。 } - return std::move(kv); + return std::move(kv);//返回一个包含所有子程序名称和描述的映射 } bool Generator::add_usage_line(const char* option, const char* default_value, - const char* description) { + const char* description) {// 是一个成员函数,它添加一个使用行到当前子程序。 std::string option_str(option); auto delimiter_pos = option_str.find(kDelimiter); - +//定义新变量,将选项字符串赋给新变量 std::string option_short; std::string option_long; - +//将选项字符串分割为短选项和长选项 if (delimiter_pos != std::string::npos) { option_short.assign(std::move(option_str.substr(0, delimiter_pos))); option_long.assign(std::move(option_str.substr(delimiter_pos + 1))); - Row row; + Row row;//创建一个Row对象, row.oshort(option_short); row.olong(option_long); row.value(default_value); row.desc(description); - - get_subroutine()->add_usage_line(row); +////设置其短选项、长选项、默认值和描述 + get_subroutine()->add_usage_line(row);//将这个Row对象添加到当前子程序的使用行中。 return true; } return false; } -std::ostream& operator<<(std::ostream& out, Generator& generator) { - for (auto pr : generator.subroutines_) { +std::ostream& operator<<(std::ostream& out, Generator& generator) {// 是一个输出运算符重载函数,它打印所有子程序的名称和描述。 + for (auto pr : generator.subroutines_) {//遍历所有的子程序 Subroutine* subroutine = pr.second; if (subroutine->get_name() != Subroutine::get_default_name()) { out << subroutine->get_name() << "\t"; + }//如果子程序的名称不是默认名称,就打印子程序的名称 + out << subroutine->get_description();//打印子程序的描述 + if (!subroutine->get_usage().empty()) {//如果子程序的使用信息不为空,就打印一个换行符 + out << std::endl;//打印一个换行符 } - out << subroutine->get_description(); - if (!subroutine->get_usage().empty()) { - out << std::endl; - } - out << *subroutine; + out << *subroutine;//打印子程序的使用信息。 } return out; } // class ParseItem -ParseItem::ParseItem(const std::string& value) : value_(value) {} +ParseItem::ParseItem(const std::string& value) : value_(value) {}//ParseItem 类的构造函数 +//它接受一个 std::string 类型的参数 value。在构造函数体中,将传入的 value 直接赋值给类的成员变量 value_。 +//这个构造函数用于创建一个 ParseItem 对象,并初始化其 value_ 成员变量。 // class Parser -ParseItem* Parser::get(const std::string& key) { - if (pr_->find(key) != pr_->end()) { - return (*pr_)[key]; +ParseItem* Parser::get(const std::string& key) {//Parser 类的 get 方法,它接受一个 std::string 类型的参数 key。 + if (pr_->find(key) != pr_->end()) {//如果 key 在 pr_ 中存在 + return (*pr_)[key];//那么返回对应的 ParseItem 指针 } - return nullptr; + return nullptr;//返回 nullptr } -Parser::Parser() : subroutines_(nullptr), pr_(nullptr) {} - +Parser::Parser() : subroutines_(nullptr), pr_(nullptr) {}// +//Parser 类的构造函数,它使用初始化列表将 subroutines_ 和 pr_ 成员变量初始化为 nullptr。 Parser::~Parser() { this->cleanup(); } - -Parser::ParseResult* Parser::parse(const int argc, const char** argv) { - if (!this->init(argc, argv)) { - return nullptr; +//这是 Parser 类的析构函数,它调用 cleanup 方法来清理资源。 +Parser::ParseResult* Parser::parse(const int argc, const char** argv) {//Parser 类的 parse 方法,它接受命令行参数的数量 argc 和参数值 argv + if (!this->init(argc, argv)) {//它调用 init 方法来初始化解析过程 + return nullptr;//如果初始化失败,那么返回 nullptr } - auto ibegin = args_.begin() + 1; // ignore the first cmd name + auto ibegin = args_.begin() + 1; // 忽略第一个命令名 auto iend = args_.end(); - auto it = ibegin; + auto it = ibegin;//定义开始变量名 if (argc >= 2 && args_[1][0] != '-') { - // the second block may be a subroutine name + // 第二个块可能是一个子程序名 // e.g., ./exec pull --option if (subroutines_ && (subroutines_->find(args_[1]) != subroutines_->end())) { subroutine_name_ = args_[1]; - it++; // ignore the subroutine name + it++; // 忽略子程序名 } else { subroutine_name_ = args_[1]; } } else { - // there is no options as well as subroutine name - // e.g., ./exec + // 没有选项以及子程序名 + // 例如,./exec subroutine_name_ = Subroutine::get_default_name(); } - std::string block; - std::string previous(*ibegin); + std::string block;//声明变量 + std::string previous(*ibegin);//声明变量 - for (; it != iend; ++it) { - block.assign(*it); + for (; it != iend; ++it) {// 遍历所有的命令行参数 + block.assign(*it);// 将当前参数赋值给 block - switch (block.size()) { - case 1: - if (block == "-") { - throw ParseError("single '-' is not allowed"); + switch (block.size()) {//// 根据 block 的大小进行不同的处理 + case 1://// 如果 block 的大小为 1 + if (block == "-") {//// 如果 block 是一个单独的 "-" + throw ParseError("single '-' is not allowed");//// 抛出异常,因为单独的 "-" 是不允许的 } break; - case 2: - if (block[0] == '-') { - if (block[1] == '-') { - throw ParseError("option '--' is incomplete"); - } else if (block[1] == '=') { - throw ParseError("option '-=' is invalid"); + case 2:// // 如果 block 的大小为 2 + if (block[0] == '-') {//// 如果 block 的第一个字符是 "-" + if (block[1] == '-') {//// 如果 block 的第二个字符也是 "-" + throw ParseError("option '--' is incomplete");//// 抛出异常,因为 "--" 是不完整的选项 + + } else if (block[1] == '=') {//// 如果 block 的第二个字符是 "=" + throw ParseError("option '-=' is invalid");//// 抛出异常,因为 "-=" 是无效的选项 } else { - // single option + // 单个选项 // e.g., ./exec -s (*pr_)[block.substr(1)] = nullptr; } } break; default: // >=3 - if (block[0] == '-') { - if (block[1] == '-') { - size_t pos_equal = block.find('='); - if (pos_equal == std::string::npos) { - // a long format option + if (block[0] == '-') {//// 如果 block 的第一个字符是 "-" + if (block[1] == '-') {//// 如果 block 的第二个字符也是 "-" + size_t pos_equal = block.find('=');//// 查找 "=" 在 block 中的位置 + if (pos_equal == std::string::npos) {//// 如果没有找到 "=" + // 长格式选项 // e.g., ./exec --option - (*pr_)[block.substr(2)] = nullptr; + (*pr_)[block.substr(2)] = nullptr;//// 将选项添加到 pr_ 中,值为 nullptr } else { - if (pos_equal > 3) { + if (pos_equal > 3) {// 如果 "=" 的位置大于 3 // e.g, ./exec --op[..=]value - std::string key(block.substr(2, pos_equal - 2)); - if (block.size() > 5) + std::string key(block.substr(2, pos_equal - 2));// 获取选项名 + if (block.size() > 5)//// 如果 block 的大小大于 5 // e.g, ./exec --op=v - (*pr_)[key] = new ParseItem(block.substr(pos_equal + 1)); + (*pr_)[key] = new ParseItem(block.substr(pos_equal + 1));// 将选项和值添加到 pr_ 中 else - (*pr_)[key] = nullptr; + (*pr_)[key] = nullptr;// 将选项添加到 pr_ 中,值为 nullptr } else { - // a long format option but = is illegal + // 长格式选项但 = 是非法的 // e.g., ./exec --o=[...] - (*pr_)[block.substr(2)] = nullptr; + (*pr_)[block.substr(2)] = nullptr;//// 将选项添加到 pr_ 中,值为 nullptr } } - } else if (block[2] == '=') { - // a single option with = + } else if (block[2] == '=') {// // 如果 block 的第三个字符是 "=" + // 单个选项带有 = // e.g., ./exec -o=[...] std::string key; - key.push_back(block[1]); - if (block.size() > 3) - (*pr_)[key] = new ParseItem(block.substr(3)); + key.push_back(block[1]);// 获取选项名 + if (block.size() > 3)// 如果 block 的大小大于 3 + (*pr_)[key] = new ParseItem(block.substr(3));//// 将选项和值添加到 pr_ 中 else - (*pr_)[key] = nullptr; + (*pr_)[key] = nullptr;// 将选项添加到 pr_ 中,值为 nullptr } else { - // a combination options + // 组合选项 // e.g., ./exec -ab[...] - auto tbegin = block.begin() + 1; // ignore the first '-' + auto tbegin = block.begin() + 1; // 忽略第一个 '-' auto tend = block.end(); auto t = tbegin; - for (; t != tend; ++t) { + for (; t != tend; ++t) { // 遍历 block 中的每个字符 std::string key; - key.push_back(*t); - (*pr_)[key] = nullptr; + key.push_back(*t);// // 获取选项名 + (*pr_)[key] = nullptr; // 将选项添加到 pr_ 中,值为 nullptr } } } break; } // switch - if (block[0] != '-' && previous != block // not the first option + if (block[0] != '-' && previous != block // 如果 block 不是选项(不以 "-" 开头)并且不是第一个选项 ) { - if (previous[0] != '-') { - // previous is not an option, error occur + if (previous[0] != '-') {//// 如果 previous 不是选项 + // previous 不是一个选项,发生错误 // e.g., ./exec abc def - throw ParseError("'" + block + "' is not allowed here"); + throw ParseError("'" + block + "' is not allowed here");//抛出异常,因为在这里不允许非选项 } std::string key; - if (previous[0] == '-' && previous[1] == '-') { + if (previous[0] == '-' && previous[1] == '-') {//// 如果 previous 是一个长格式选项 // previous is a long format option. // e.g., ./exec --option value - key = previous.substr(2); + key = previous.substr(2);//// 获取选项名 } else { - // it's the value of previous option. + // 它是前一个选项的值。 // e.g., ./exec -o [...] // e.g., ./exec -opq [...] - key.push_back(*(previous.end() - 1)); + key.push_back(*(previous.end() - 1));// // 获取选项名 } - if (pr_->find(key) != pr_->end()) { - (*pr_)[key] = new ParseItem(block); + if (pr_->find(key) != pr_->end()) {//// 如果选项在 pr_ 中存在 + (*pr_)[key] = new ParseItem(block); // 将选项和值添加到 pr_ 中 } } - previous = block; + previous = block;//// 更新 previous 为当前的 block } // for if (subroutines_) { - this->set_addition(); + this->set_addition();// 如果存在子程序,调用 set_addition 方法处理额外的选项 } - return pr_; + return pr_;//返回解析结果 pr_ } -Parser::ParseResult* Parser::parse(const char* command_line) { - int i = 0; - std::string block; - std::vector blocks; - char c; - while ((c = command_line[i++]) != '\0') { - if (c != ' ') { - block.push_back(c); +Parser::ParseResult* Parser::parse(const char* command_line) {//Parser 类的 parse 方法 + int i = 0;//初始化计数器 + std::string block;//用于存储单个命令行参数 + std::vector blocks;//声明用于存储所有命令行参数 + char c;//声明用于存储当前字符 + while ((c = command_line[i++]) != '\0') {// 遍历命令行字符串 + if (c != ' ') {// 如果当前字符不是空格 + block.push_back(c);//// 将当前字符添加到 block } else { - if (!block.empty()) { - blocks.push_back(block); + if (!block.empty()) {// 如果 block 不为空 + blocks.push_back(block);// 将 block 添加到 blocks } - block.clear(); + block.clear();//清空 block } } - if (!block.empty()) { - blocks.push_back(block); + if (!block.empty()) {// 如果最后一个 block 不为空 + blocks.push_back(block);// 将 block 添加到 blocks } size_t size = blocks.size(); // argc - char** argv = new char*[size]; + char** argv = new char*[size];// 创建一个新的 char* 数组 i = 0; - std::for_each(blocks.begin(), blocks.end(), [argv, &i](const std::string& b) { - argv[i++] = const_cast(b.c_str()); + std::for_each(blocks.begin(), blocks.end(), [argv, &i](const std::string& b) {// 遍历 blocks + argv[i++] = const_cast(b.c_str());// 将每个 block 转换为 char* 并存储在 argv 中 }); auto pr = - this->parse(static_cast(size), const_cast(argv)); + this->parse(static_cast(size), const_cast(argv)); // 调用 parse 方法解析命令行参数 - delete[] argv; + delete[] argv;// 删除 argv argv = nullptr; - return pr; + return pr;// 返回解析结果 } -bool Parser::has(const char* key) { - std::string skey(key); +bool Parser::has(const char* key) {//Parser 类的 has 方法,它接受一个 char 指针 key,并检查 key 是否在 pr_ 中存在。 + std::string skey(key);// 将 key 转换为 std::string - if (pr_ && !pr_->empty() && !skey.empty()) { + if (pr_ && !pr_->empty() && !skey.empty()) {//判断是否存在 if (skey[0] == '-') { - // check combination options, e.g., Parser::has("-xyz") - for (size_t i = 1; i < skey.size(); ++i) { + // 如果 skey 是一个组合选项,例如 "-xyz" + for (size_t i = 1; i < skey.size(); ++i) {// 遍历 skey 的每个字符 std::string tkey; - tkey.push_back(skey[i]); - if (pr_->find(tkey) == pr_->end()) { + tkey.push_back(skey[i]);// 获取选项名 + if (pr_->find(tkey) == pr_->end()) { // 如果选项名在 pr_ 中不存在 return false; } } return true; } else { - // check single option, e.g., Parser::has("x") - return pr_->find(skey) != pr_->end(); + // 如果 skey 是一个单个选项,例如 "x" + return pr_->find(skey) != pr_->end();// 检查选项是否在 pr_ 中存在 } } - return false; + return false;// 如果 pr_ 为空或 skey 为空,返回 false } +//parser 类的 has_or 方法,它接受一个初始化列表 options,并检查 options 中的任何一个 key 是否在 pr_ 中存在。 bool Parser::has_or(std::initializer_list options) { - if (options.size() == 0) { + if (options.size() == 0) {// 如果 options 为空 return false; + }4 + for (auto key : options) {// 遍历 options 中的每个选项 + if (this->has(key)) return true;// 如果选项在 pr_ 中存在,返回 true } - for (auto key : options) { - if (this->has(key)) return true; - } - return false; + return false;// 如果 options 中的所有选项都不存在,返回 false } -bool Parser::has_and(std::initializer_list options) { - if (options.size() == 0) { +bool Parser::has_and(std::initializer_list options) { // Parser 类的 has_and 方法,接受一个初始化列表 options + if (options.size() == 0) {// 如果 options 为空 return false; } - for (auto key : options) { - if (!this->has(key)) return false; + for (auto key : options) {// 遍历 options 中的每个选项 + if (!this->has(key)) return false;// 如果选项在 pr_ 中不存在,返回 false } - return true; + return true;// 如果 options 中的所有选项都存在,返回 true } bool Parser::init(const int argc, const char** argv) { - argc_ = argc; + argc_ = argc;// 保存参数数量 // argv_ = argv; // don't save it, point to a local var in parse(const char* command_line). // use member var args_ instead. - if (argc > 0) { - this->cleanup(); + if (argc > 0) {// 如果参数数量大于 0 + this->cleanup(); // 清理之前的解析结果 + - args_.reserve(static_cast(argc_)); + args_.reserve(static_cast(argc_));// 为 args_ 预留空间 - for (int i = 0; i < argc_; ++i) { - args_.push_back(argv[i]); + for (int i = 0; i < argc_; ++i) {// 遍历所有的命令行参数 + args_.push_back(argv[i]);// 将参数添加到 args_ } - pr_ = new Parser::ParseResult; + pr_ = new Parser::ParseResult;// 创建新的解析结果 return true; } - return false; + return false;// 如果参数数量为 0,返回 false } -void Parser::cleanup() { - args_.clear(); - if (pr_) { +void Parser::cleanup() {// Parser 类的 cleanup 方法,用于清理解析结果 + args_.clear();// 清空 args_ + if (pr_) {// 如果 pr_ 不为空 auto ibegin = pr_->begin(); auto iend = pr_->end(); auto it = ibegin; - for (; it != iend; ++it) { + for (; it != iend; ++it) {// 遍历 pr_ 中的每个元素 ParseItem* item = it->second; - if (item) delete item; + if (item) delete item;// 删除元素 } - delete pr_; + delete pr_;// 删除 pr_ pr_ = nullptr; } } -void Parser::set_addition() { - if (subroutines_->find(subroutine_name_) != subroutines_->end()) { - for (const Row& row : *(subroutines_->at(subroutine_name_))) { +void Parser::set_addition() {// Parser 类的 set_addition 方法,用于处理额外的选项 + if (subroutines_->find(subroutine_name_) != subroutines_->end()) {// 如果子程序名在 subroutines_ 中存在 + for (const Row& row : *(subroutines_->at(subroutine_name_))) {// 遍历子程序中的每一行 // assume both -o and --option are allowed, // but only provide -o, // then set the another --option. // vice versa. - const std::string& def = row.value(); - const std::string& ops = row.oshort(); - const std::string& opl = row.olong(); - ParseResult& pr = *pr_; + const std::string& def = row.value();// 获取默认值 + const std::string& ops = row.oshort();// 获取短选项 + const std::string& opl = row.olong();// 获取长选项 + ParseResult& pr = *pr_; // 获取解析结果 - bool has_short = this->has(ops.c_str()); - bool has_long = this->has(opl.c_str()); + bool has_short = this->has(ops.c_str());// 检查短选项是否存在 + bool has_long = this->has(opl.c_str());// 检查长选项是否存在 // assume -o [ --option ] arg = 1 // but not provide option value, // then set to default 1. // otherwise, both set to user defined value - if (!ops.empty()) { - if (has_short) { - if (pr[ops] != nullptr && !opl.empty()) { - pr[opl] = new ParseItem(std::move(pr[ops]->val())); - } else if (pr[ops] == nullptr && !def.empty()) { - pr[ops] = new ParseItem(std::move(def)); - if (!opl.empty()) pr[opl] = new ParseItem(std::move(def)); + if (!ops.empty()) {// 如果短选项不为空 + if (has_short) {// 如果短选项存在 + if (pr[ops] != nullptr && !opl.empty()) {// 如果短选项有值且长选项不为空 + pr[opl] = new ParseItem(std::move(pr[ops]->val()));// 将短选项的值赋给长选项 + } else if (pr[ops] == nullptr && !def.empty()) {// 如果短选项没有值且默认值不为空 + pr[ops] = new ParseItem(std::move(def));// 将默认值赋给短选项 + if (!opl.empty()) pr[opl] = new ParseItem(std::move(def));// 如果长选项不为空,也将默认值赋给长选项 } else { - pr[opl] = nullptr; + pr[opl] = nullptr;// 将长选项的值设为 nullptr } } } - if (!opl.empty()) { - if (has_long) { - if (pr[opl] != nullptr && !ops.empty()) { - pr[ops] = new ParseItem(std::move(pr[opl]->val())); - } else if (pr[opl] == nullptr && !def.empty()) { - if (!ops.empty()) pr[ops] = new ParseItem(std::move(def)); - pr[opl] = new ParseItem(std::move(def)); + if (!opl.empty()) {// 如果长选项不为空 + if (has_long) { // 如果长选项存在 + if (pr[opl] != nullptr && !ops.empty()) { // 如果长选项有值且短选项不为空 + pr[ops] = new ParseItem(std::move(pr[opl]->val()));// 将长选项的值赋给短选项 + } else if (pr[opl] == nullptr && !def.empty()) {// 如果长选项没有值且默认值不为空 + if (!ops.empty()) pr[ops] = new ParseItem(std::move(def));// 如果短选项不为空,将默认值赋给短选项 + pr[opl] = new ParseItem(std::move(def));// 将默认值赋给长选项 } else { - pr[ops] = nullptr; + pr[ops] = nullptr;// 将短选项的值设为 nullptr } } } - if (!has_long && !has_short && !def.empty()) { - if (!opl.empty()) pr[opl] = new ParseItem(std::move(def)); - if (!ops.empty()) pr[ops] = new ParseItem(std::move(def)); + if (!has_long && !has_short && !def.empty()) {// 如果长选项和短选项都不存在且默认值不为 + if (!opl.empty()) pr[opl] = new ParseItem(std::move(def));// 如果长选项不为空,将默认值赋给长选项 + if (!ops.empty()) pr[ops] = new ParseItem(std::move(def));// 如果短选项不为空,将默认值赋给短选项 } } // for } // if @@ -427,114 +433,115 @@ void Parser::set_addition() { // class Row -Row::Row() : require_value(true) {} +Row::Row() : require_value(true) {} // Row 类的构造函数,初始化 require_value 为 true // class Subroutine -Subroutine::Subroutine() : first_line_("") {} +Subroutine::Subroutine() : first_line_("") {}// Subroutine 类的默认构造函数,初始化 first_line_ 为空字符串 Subroutine::Subroutine(const char* name, const char* description) - : first_line_(""), description_(description), name_(name) { - usages_.reserve(5); + : first_line_(""), description_(description), name_(name) { // Subroutine 类的构造函数,接受子程序名和描述作为参数 + usages_.reserve(5);// 为 usages_ 预留空间 } -void Subroutine::print_with_row(std::ostream& out) { +void Subroutine::print_with_row(std::ostream& out) {// Subroutine 类的 print_with_row 方法,接受一个输出流作为参数 // print the subroutine name and its description - if (strcmp(get_first_line(), "") != 0) { + // 打印子程序名和描述 + if (strcmp(get_first_line(), "") != 0) {// 如果 first_line_ 不为空 // print the first line out << get_first_line(); - if (!usages_.empty()) { - out << std::endl; + if (!usages_.empty()) {// 如果 usages_ 不为空 + out << std::endl;// 打印换行符 } } - auto begin = usages_.begin(); - auto end = usages_.end(); + auto begin = usages_.begin(); // 获取 usages_ 的开始迭代器 + auto end = usages_.end();// 获取 usages_ 的结束迭代器 - std::vector row_list; - row_list.reserve(usages_.size()); + std::vector row_list;// 创建一个字符串向量用于存储行 + row_list.reserve(usages_.size());// 为 row_list 预留空间 // build usage rows without description field, // find the max-len row at the same time. size_t max_len = 0; - std::for_each(begin, end, [&max_len, &row_list](const Row& row) { - std::stringstream ss; - ss << " "; - if (!row.oshort().empty()) { - ss << "-" << row.oshort() << " "; + std::for_each(begin, end, [&max_len, &row_list](const Row& row) {// 遍历 usages_ + std::stringstream ss;// 创建一个字符串流 + ss << " ";// 向字符串流中添加两个空格 + if (!row.oshort().empty()) {// 如果短选项不为空 + ss << "-" << row.oshort() << " "; // 添加短选项 } - if (!row.olong().empty()) { + if (!row.olong().empty()) {// 如果长选项不为空 if (!row.oshort().empty()) - ss << "[ --" << row.olong() << " ] "; + ss << "[ --" << row.olong() << " ] ";// 添加长选项 else - ss << "--" << row.olong() << " "; + ss << "--" << row.olong() << " "; // 添加长选项 } - if (row.required()) { - ss << "arg "; - if (!row.value().empty()) { - ss << "= " << row.value() << " "; + if (row.required()) {// 如果选项是必需的 + ss << "arg "; // 添加 "arg " + if (!row.value().empty()) {// 如果选项值不为空 + ss << "= " << row.value() << " ";// 添加选项值 } } - max_len = std::max(max_len, ss.str().size()); - row_list.push_back(std::move(ss.str())); + max_len = std::max(max_len, ss.str().size());// 更新最大长度 + row_list.push_back(std::move(ss.str()));// 将字符串流的内容添加到 row_list }); // show all rows and align description field - size_t row_count = usages_.size(); - for (size_t i = 0; i < row_count; ++i) { - std::string str_row(std::move(row_list[i])); + size_t row_count = usages_.size();// 获取 usages_ 的大小 + for (size_t i = 0; i < row_count; ++i) {// 遍历 usages_ + std::string str_row(std::move(row_list[i]));// 获取当前行 // print row without description - out << str_row; + out << str_row;// 打印当前行 // print spaces - size_t spaces = 0; - size_t len = str_row.size(); - if (max_len > len) spaces = max_len - len; + size_t spaces = 0;// 打印空格 + size_t len = str_row.size();// 获取当前行的长度 + if (max_len > len) spaces = max_len - len;// 计算需要打印的空格数量 - while (spaces--) { + while (spaces--) {// 打印空格 out << " "; } // print description - out << usages_.at(i).desc() << std::endl; + out << usages_.at(i).desc() << std::endl;// 打印描述 } } -void Subroutine::print_with_template(std::ostream& out) { - for (auto usage : usages_) { +void Subroutine::print_with_template(std::ostream& out) {// Subroutine 类的 print_with_template 方法,接受一个输出流作为参数 + for (auto usage : usages_) {// 遍历 usages_ size_t i = 0; - for (auto t = template_str_.begin(); t != template_str_.end(); ++t) { - if (*t == '%') { - switch (*(order_.begin() + i)) { + for (auto t = template_str_.begin(); t != template_str_.end(); ++t) {// 遍历模板字符串 + if (*t == '%') {// 如果当前字符是 '%' + switch (*(order_.begin() + i)) { // 根据 order_ 中的值决定打印哪个字段 case Row::kShort: - out << usage.oshort(); + out << usage.oshort();// 打印短选项 break; case Row::kLong: - out << usage.olong(); + out << usage.olong();// 打印长选项 break; case Row::kDefault: - out << usage.value(); + out << usage.value();// 打印默认值 break; case Row::kDescription: - out << usage.desc(); + out << usage.desc();// 打印描述 break; default: break; } ++i; } else { - out << *t; + out << *t;// 如果当前字符不是 '%',直接打印 } // if % } // for template_str_ - out << std::endl; + out << std::endl;// 打印换行符 } // for usages_ } -std::ostream& operator<<(std::ostream& out, Subroutine& subroutine) { - if (subroutine.template_str_.empty()) { - subroutine.print_with_row(out); +std::ostream& operator<<(std::ostream& out, Subroutine& subroutine) {// 重载 << 运算符,接受一个输出流和一个 Subroutine 对象作为参数 + if (subroutine.template_str_.empty()) {// 如果模板字符串为空 + subroutine.print_with_row(out);// 使用 print_with_row 方法打印 } else { - subroutine.print_with_template(out); + subroutine.print_with_template(out);// 使用 print_with_template 方法打印 } - return out; + return out;// 返回输出流 } } \ No newline at end of file diff --git a/src/src/util/util.cpp b/src/src/util/util.cpp index b293c2a..df37418 100644 --- a/src/src/util/util.cpp +++ b/src/src/util/util.cpp @@ -1,127 +1,127 @@ #include "easypr/util/util.h" #include -#ifdef OS_WINDOWS -#include -#include -#include -#define PATH_DELIMITER '\\' +// #ifdef OS_WINDOWS +#include // 包含windows.h头文件,用于Windows平台的系统调用 +#include // 包含direct.h头文件,用于Windows平台的目录操作 +#include // 包含io.h头文件,用于Windows平台的IO操作 +#define PATH_DELIMITER '\\' // 定义路径分隔符为'\\' #ifdef min -#undef min +#undef min // 如果已经定义了min,取消其定义 #endif #ifdef max -#undef max +#undef max // 如果已经定义了max,取消其定义 #endif #elif defined(OS_LINUX) || defined(OS_UNIX) -#include -#include -#include -#include +#include // 包含cstring头文件,用于字符串操作 +#include // 包含dirent.h头文件,用于目录操作 +#include // 包含sys/stat.h头文件,用于文件状态检查 +#include // 包含unistd.h头文件,用于Unix标准的系统调用 -#define PATH_DELIMITER '/' +#define PATH_DELIMITER '/' // 定义路径分隔符为'/' #endif #ifdef OS_UNIX -#include +#include // 包含sys/timeb.h头文件,用于时间操作 #endif -#include -#include +#include // 包含list头文件,用于list数据结构 +#include // 包含opencv的highgui模块,用于图像IO操作 -namespace easypr { +namespace easypr { // 定义easypr命名空间 -long Utils::getTimestamp() { +long Utils::getTimestamp() { // 定义获取时间戳的函数 #ifdef OS_WINDOWS - return static_cast(cv::getTickCount()); + return static_cast(cv::getTickCount()); // Windows平台下,使用opencv的getTickCount函数获取时间戳 #endif #ifdef OS_LINUX - struct timespec ts; + struct timespec ts; // 定义timespec结构体,用于获取时间 - clock_gettime(CLOCK_MONOTONIC, &ts); + clock_gettime(CLOCK_MONOTONIC, &ts); // 获取当前时间 - return (ts.tv_sec * 1e3 + ts.tv_nsec / 1e6); + return (ts.tv_sec * 1e3 + ts.tv_nsec / 1e6); // 返回毫秒级的时间戳 #endif #ifdef OS_UNIX // there is no function provided by osx to get system tick count. // but considering the purpose by using this function, // we can simply return a millisecond since 1970/1/1 to calc the time elapse. - struct timeb tb; - ftime(&tb); - return long(tb.time * 1e3 + tb.millitm); + struct timeb tb; // 定义timeb结构体,用于获取时间 + ftime(&tb); // 获取当前时间 + return long(tb.time * 1e3 + tb.millitm); // 返回毫秒级的时间戳 #endif } std::string Utils::getFileName(const std::string &path, - const bool postfix /* = false */) { - if (!path.empty()) { - size_t last_slash = utils::get_last_slash(path); - size_t last_dot = path.find_last_of('.'); + const bool postfix /* = false */) { // 定义获取文件名的函数 + if (!path.empty()) { // 如果路径不为空 + size_t last_slash = utils::get_last_slash(path); // 获取路径中最后一个斜杠的位置 + size_t last_dot = path.find_last_of('.'); // 获取路径中最后一个点的位置 if (last_dot < last_slash || last_dot == std::string::npos) { // not found the right dot of the postfix, // return the file name directly - return path.substr(last_slash + 1); + return path.substr(last_slash + 1); // 如果没有找到正确的后缀点,直接返回文件名 } else { // the path has a postfix if (postfix) { // return the file name including postfix - return path.substr(last_slash + 1); + return path.substr(last_slash + 1); // 如果路径有后缀,并且需要返回后缀,返回包含后缀的文件名 } // without postfix - return path.substr(last_slash + 1, last_dot - last_slash - 1); + return path.substr(last_slash + 1, last_dot - last_slash - 1); // 如果路径有后缀,但不需要返回后缀,返回不包含后缀的文件名 } } - return ""; + return ""; // 如果路径为空,返回空字符串 } std::vector Utils::splitString(const std::string &str, - const char delimiter) { - std::vector splited; - std::string s(str); - size_t pos; + const char delimiter) { // 定义字符串分割函数 + std::vector splited; // 定义存储分割结果的vector + std::string s(str); // 复制输入的字符串 + size_t pos; // 定义分割位置 - while ((pos = s.find(delimiter)) != std::string::npos) { - std::string sec = s.substr(0, pos); + while ((pos = s.find(delimiter)) != std::string::npos) { // 当找到分隔符时 + std::string sec = s.substr(0, pos); // 获取分隔符前的子串 - if (!sec.empty()) { - splited.push_back(s.substr(0, pos)); + if (!sec.empty()) { // 如果子串不为空 + splited.push_back(s.substr(0, pos)); // 将子串添加到分割结果中 } - s = s.substr(pos + 1); + s = s.substr(pos + 1); // 更新待分割的字符串 } - splited.push_back(s); + splited.push_back(s); // 将最后一个子串添加到分割结果中 - return splited; + return splited; // 返回分割结果 } std::vector Utils::getFiles(const std::string &folder, - const bool all /* = true */) { - std::vector files; - std::list subfolders; - subfolders.push_back(folder); + const bool all /* = true */) { // 定义获取文件列表的函数 + std::vector files; // 定义存储文件列表的vector + std::list subfolders; // 定义存储子文件夹的list + subfolders.push_back(folder); // 将输入的文件夹添加到子文件夹列表中 #ifdef OS_WINDOWS - while (!subfolders.empty()) { - std::string current_folder(subfolders.back()); + while (!subfolders.empty()) { // 当子文件夹列表不为空时 + std::string current_folder(subfolders.back()); // 获取当前处理的文件夹 if (*(current_folder.end() - 1) != '/') { - current_folder.append("/*"); + current_folder.append("/*"); // 如果当前文件夹的路径不以'/'结尾,添加'/*' } else { - current_folder.append("*"); + current_folder.append("*"); // 如果当前文件夹的路径以'/'结尾,添加'*' } - subfolders.pop_back(); + subfolders.pop_back(); // 从子文件夹列表中移除当前处理的文件夹 - struct _finddata_t file_info; - auto file_handler = _findfirst(current_folder.c_str(), &file_info); + struct _finddata_t file_info; // 定义文件信息结构体 + auto file_handler = _findfirst(current_folder.c_str(), &file_info); // 打开当前文件夹 - while (file_handler != -1) { + while (file_handler != -1) { // 当文件夹打开成功时 if (all && (!strcmp(file_info.name, ".") || !strcmp(file_info.name, ".."))) { if (_findnext(file_handler, &file_info) != 0) break; @@ -136,7 +136,7 @@ std::vector Utils::getFiles(const std::string &folder, folder.pop_back(); folder.append(file_info.name); - subfolders.push_back(folder.c_str()); + subfolders.push_back(folder.c_str()); // 如果是子文件夹,并且需要搜索子文件夹,将子文件夹添加到子文件夹列表中 } } else { // it's a file @@ -145,24 +145,24 @@ std::vector Utils::getFiles(const std::string &folder, file_path.assign(current_folder.c_str()).pop_back(); file_path.append(file_info.name); - files.push_back(file_path); + files.push_back(file_path); // 如果是文件,将文件路径添加到文件列表中 } if (_findnext(file_handler, &file_info) != 0) break; } // while - _findclose(file_handler); + _findclose(file_handler); // 关闭文件夹 } #elif defined(OS_LINUX) || defined(OS_UNIX) - while (!subfolders.empty()) { - std::string current_folder(subfolders.back()); + while (!subfolders.empty()) { // 当子文件夹列表不为空时 + std::string current_folder(subfolders.back()); // 获取当前处理的文件夹 if (*(current_folder.end() - 1) != '/') { - current_folder.push_back('/'); + current_folder.push_back('/'); // 如果当前文件夹的路径不以'/'结尾,添加'/' } - DIR* pdir = opendir(current_folder.c_str()); + DIR* pdir = opendir(current_folder.c_str()); // 打开当前文件夹 - subfolders.pop_back(); + subfolders.pop_back(); // 从子文件夹列表中移除当前处理的文件夹 if (!pdir) { continue; @@ -170,9 +170,9 @@ std::vector Utils::getFiles(const std::string &folder, dirent* dir = NULL; - while ((dir = readdir(pdir)) != NULL) { + while ((dir = readdir(pdir)) != NULL) { // 当读取到文件或文件夹时 // iterates the current folder, search file & sub folder - struct stat st; + struct stat st; // 定义文件状态结构体 if (all && (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))) { // must ignore . & .. @@ -201,93 +201,93 @@ std::vector Utils::getFiles(const std::string &folder, std::string subfolder(current_folder); subfolder.append(dir->d_name); - subfolders.push_back(subfolder.c_str()); + subfolders.push_back(subfolder.c_str()); // 如果是子文件夹,并且需要搜索子文件夹,将子文件夹添加到子文件夹列表中 } } else { // it's a file - files.push_back(file_path); + files.push_back(file_path); // 如果是文件,将文件路径添加到文件列表中 } } // while - closedir(pdir); + closedir(pdir); // 关闭文件夹 } #endif - return files; + return files; // 返回文件列表 } -bool Utils::mkdir(const std::string folder) { - std::string folder_builder; - std::string sub; +bool Utils::mkdir(const std::string folder) { // 定义创建文件夹的函数 + std::string folder_builder; // 定义文件夹路径构造器 + std::string sub; // 定义子路径 sub.reserve(folder.size()); - for (auto it = folder.begin(); it != folder.end(); ++it) { + for (auto it = folder.begin(); it != folder.end(); ++it) { // 遍历输入的文件夹路径 const char c = *it; sub.push_back(c); - if (c == PATH_DELIMITER || it == folder.end() - 1) { - folder_builder.append(sub); + if (c == PATH_DELIMITER || it == folder.end() - 1) { // 当遇到路径分隔符或路径结束时 + folder_builder.append(sub); // 将子路径添加到文件夹路径构造器中 #ifdef OS_WINDOWS - if (0 != ::_access(folder_builder.c_str(), 0)) { + if (0 != ::_access(folder_builder.c_str(), 0)) { // 如果文件夹不存在 #else - if (0 != ::access(folder_builder.c_str(), 0)) { + if (0 != ::access(folder_builder.c_str(), 0)) { // 如果文件夹不存在 #endif // this folder not exist #ifdef OS_WINDOWS - if (0 != ::_mkdir(folder_builder.c_str())) { + if (0 != ::_mkdir(folder_builder.c_str())) { // 如果创建文件夹失败 #else - if (0 != ::mkdir(folder_builder.c_str(), S_IRWXU)) { + if (0 != ::mkdir(folder_builder.c_str(), S_IRWXU)) { // 如果创建文件夹失败 #endif // create failed - return false; + return false; // 返回失败 } } - sub.clear(); + sub.clear(); // 清空子路径 } } - return true; + return true; // 返回成功 } -bool Utils::imwrite(const std::string &file, const cv::Mat &image) { - auto folder = file.substr(0, utils::get_last_slash(file)); - Utils::mkdir(folder); - return cv::imwrite(file, image); +bool Utils::imwrite(const std::string &file, const cv::Mat &image) { // 定义图像写入函数 + auto folder = file.substr(0, utils::get_last_slash(file)); // 获取文件所在的文件夹 + Utils::mkdir(folder); // 创建文件所在的文件夹 + return cv::imwrite(file, image); // 写入图像 } #ifdef OS_WINDOWS -std::string Utils::utf8_to_gbk(const char* utf8) { - int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); - wchar_t* wszGBK = new wchar_t[len + 1]; - memset(wszGBK, 0, len * 2 + 2); - MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wszGBK, len); - len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); - char* szGBK = new char[len + 1]; - memset(szGBK, 0, len + 1); - WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); - std::string strTemp(szGBK); +std::string Utils::utf8_to_gbk(const char* utf8) { // 定义UTF-8到GBK的转换函数 + int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); // 获取转换后的长度 + wchar_t* wszGBK = new wchar_t[len + 1]; // 定义存储转换结果的宽字符数组 + memset(wszGBK, 0, len * 2 + 2); // 初始化宽字符数组 + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wszGBK, len); // 将UTF-8字符串转换为宽字符字符串 + len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); // 获取转换后的长度 + char* szGBK = new char[len + 1]; // 定义存储转换结果的字符数组 + memset(szGBK, 0, len + 1); // 初始化字符数组 + WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); // 将宽字符字符串转换为GBK字符串 + std::string strTemp(szGBK); // 将GBK字符串转换为std::string if (wszGBK) - delete[] wszGBK; + delete[] wszGBK; // 删除宽字符数组 if (szGBK) - delete[] szGBK; - return strTemp; + delete[] szGBK; // 删除字符数组 + return strTemp; // 返回转换结果 } #endif -std::size_t Utils::get_last_slash(const std::string &path) { +std::size_t Utils::get_last_slash(const std::string &path) { // 定义获取路径中最后一个斜杠的位置的函数 #ifdef OS_WINDOWS - size_t last_slash_1 = path.find_last_of("\\"); - size_t last_slash_2 = path.find_last_of("/"); + size_t last_slash_1 = path.find_last_of("\\"); // 获取路径中最后一个'\\'的位置 + size_t last_slash_2 = path.find_last_of("/"); // 获取路径中最后一个'/'的位置 size_t last_slash; if (last_slash_1 != std::string::npos && last_slash_2 != std::string::npos) { // C:/path\\to/file.postfix - last_slash = std::max(last_slash_1, last_slash_2); + last_slash = std::max(last_slash_1, last_slash_2); // 如果路径中既有'\\'又有'/',取最后出现的一个 } else { // C:\\path\\to\\file.postfix // C:/path/to/file.postfix last_slash = - (last_slash_1 == std::string::npos) ? last_slash_2 : last_slash_1; + (last_slash_1 == std::string::npos) ? last_slash_2 : last_slash_1; // 如果路径中只有'\\'或只有'/',取出现的那一个 } #else - size_t last_slash = path.find_last_of('/'); + size_t last_slash = path.find_last_of('/'); // 获取路径中最后一个'/'的位置 #endif - return last_slash; + return last_slash; // 返回最后一个斜杠的位置 } } // namespace easypr \ No newline at end of file