develop
heureux 11 months ago
parent e4f6eba330
commit 5eca185d11

@ -1,81 +1,81 @@
#include "easypr/util/kv.h" #include "easypr/util/kv.h" // 引入kv头文件
#include "easypr/util/util.h" #include "easypr/util/util.h" // 引入util头文件
namespace easypr { namespace easypr { // 定义easypr命名空间
Kv::Kv() { } Kv::Kv() { } // Kv类构造函数
void Kv::load(const std::string &file) { void Kv::load(const std::string &file) { // 加载文件
this->clear(); this->clear(); // 清空数据
std::ifstream reader(file); std::ifstream reader(file); // 创建文件读取流
assert(reader); assert(reader); // 断言文件读取流创建成功
if (reader.is_open()) { if (reader.is_open()) { // 如果文件打开成功
while (!reader.eof()) { while (!reader.eof()) { // 当未到达文件末尾时
std::string line; std::string line; // 定义字符串变量line
std::getline(reader, line); std::getline(reader, line); // 读取一行数据到line
if (line.empty()) continue; if (line.empty()) continue; // 如果line为空则跳过本次循环
const auto parse = [](const std::string &str) { const auto parse = [](const std::string &str) { // 定义解析函数
std::string tmp, key, value; std::string tmp, key, value; // 定义临时变量、键、值
for (size_t i = 0, len = str.length(); i < len; ++i) { for (size_t i = 0, len = str.length(); i < len; ++i) { // 遍历字符串
const char ch = str[i]; const char ch = str[i]; // 获取当前字符
if (ch == ' ') { if (ch == ' ') { // 如果当前字符为空格
if (i > 0 && str[i - 1] != ' ' && key.empty()) { if (i > 0 && str[i - 1] != ' ' && key.empty()) { // 如果前一个字符不为空格且键为空
key = tmp; key = tmp; // 将临时变量赋值给键
tmp.clear(); tmp.clear(); // 清空临时变量
} }
} }
else { else {
tmp.push_back(ch); tmp.push_back(ch); // 将当前字符添加到临时变量
} }
if (i == len - 1) { if (i == len - 1) { // 如果当前字符是最后一个字符
value = tmp; value = tmp; // 将临时变量赋值给值
} }
} }
return std::make_pair(key, value); return std::make_pair(key, value); // 返回键值对
}; };
auto kv = parse(line); auto kv = parse(line); // 解析行数据
this->add(kv.first, kv.second); this->add(kv.first, kv.second); // 添加键值对
} }
reader.close(); reader.close(); // 关闭文件读取流
} }
} }
std::string Kv::get(const std::string &key) { std::string Kv::get(const std::string &key) { // 获取键对应的值
if (data_.find(key) == data_.end()) { if (data_.find(key) == data_.end()) { // 如果键不存在
std::cerr << "[Kv] cannot find " << key << std::endl; std::cerr << "[Kv] cannot find " << key << std::endl; // 输出错误信息
return ""; return ""; // 返回空字符串
} }
return data_.at(key); return data_.at(key); // 返回键对应的值
} }
void Kv::add(const std::string &key, const std::string &value) { void Kv::add(const std::string &key, const std::string &value) { // 添加键值对
if (data_.find(key) != data_.end()) { if (data_.find(key) != data_.end()) { // 如果键已存在
fprintf(stderr, fprintf(stderr,
"[Kv] find duplicate: %s = %s , ignore\n", "[Kv] find duplicate: %s = %s , ignore\n",
key.c_str(), key.c_str(),
value.c_str()); value.c_str()); // 输出错误信息
} else { } else {
std::string v(value); std::string v(value);
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
v = utils::utf8_to_gbk(value.c_str()); v = utils::utf8_to_gbk(value.c_str());()); // 如果是Windows系统将值转换为gbk编码
#endif #endif
data_[key] = v; data_[key] = v; // 添加键值对
} }
} }
void Kv::remove(const std::string &key) { void Kv::remove(const std::string &key) { // 删除键值对
if (data_.find(key) == data_.end()) { if (data_.find(key) == data_.end()) { // 如果键不存在
std::cerr << "[Kv] cannot find " << key << std::endl; std::cerr << "[Kv] cannot find " << key << std::endl; // 输出错误信息
return; return; // 返回
} }
data_.erase(key); data_.erase(key); // 删除键值对
} }
void Kv::clear() { void Kv::clear() { // 清空数据
data_.clear(); data_.clear(); // 清空数据
} }
} }

@ -3,423 +3,429 @@
namespace program_options { namespace program_options {
// class ParseError // class ParseError
//定义了一个名为ParseError的类
ParseError::ParseError(const std::string& msg) : _msg(msg) {} //ParseError类是一个用于处理命令行解析错误的异常类。
ParseError::ParseError(const std::string& msg) : _msg(msg) {}//是ParseError类的构造函数
const char* ParseError::what() const throw() { //它接受一个字符串作为参数并将这个字符串赋值给成员变量_msg。
std::string msg; const char* ParseError::what() const throw() {//是一个成员函数,它返回一个描述错误的字符串
msg.append("Command line parse error: ").append(_msg).push_back('.'); std::string msg;//首先创建一个新的字符串
return msg.c_str(); 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 // class Generator
//定义了一个名为Generator的类该类用于生成和管理命令行选项解析器和子程序。
Generator::Generator() : parser_(nullptr) { Generator::Generator() : parser_(nullptr) {//Generator类的构造函数
current_subroutine_ = Subroutine::get_default_name(); current_subroutine_ = Subroutine::get_default_name();//初始化parser_为nullptr设置当前子程序为默认子程序
add_subroutine(current_subroutine_.c_str()); add_subroutine(current_subroutine_.c_str());//添加这个子程序。
} }
Generator::~Generator() { Generator::~Generator() {//Generator类的析构函数
if (parser_) { if (parser_) {
delete parser_; delete parser_;
parser_ = nullptr; parser_ = nullptr;
} }//它删除parser_和所有的子程序
for (auto it = subroutines_.begin(); it != subroutines_.end(); ++it) { for (auto it = subroutines_.begin(); it != subroutines_.end(); ++it) {
if (it->second) { if (it->second) {
delete it->second; delete it->second;//它删除所有的子程序,
it->second = nullptr; it->second = nullptr;//并将parser_和所有的子程序设置为nullptr。
} }
} }
} }
Generator& Generator::make_usage(const char* first_line) { Generator& Generator::make_usage(const char* first_line) {//是一个成员函数
get_subroutine()->set_first_line(first_line); get_subroutine()->set_first_line(first_line);//它设置当前子程序的第一行
return *this; return *this;//并返回this指针。
} }
Parser* Generator::make_parser() { Parser* Generator::make_parser() {//是一个成员函数
if (parser_) delete parser_; if (parser_) delete parser_;
parser_ = new Parser; parser_ = new Parser;//它创建一个新的Parser对象
parser_->set_usage_subroutines(&subroutines_); parser_->set_usage_subroutines(&subroutines_);//设置其使用的子程序
return parser_; return parser_;//并返回这个Parser对象。
} }
Generator& Generator::add_subroutine(const char* name) { Generator& Generator::add_subroutine(const char* name) {//是成员函数
add_subroutine(name, ""); add_subroutine(name, "");//它们添加一个新的子程序。
return *this; return *this;
} }
Generator& Generator::add_subroutine(const char* name, Generator& Generator::add_subroutine(const char* name,
const char* description) { const char* description) {//成员函数
if (subroutines_.find(name) == subroutines_.end()) { if (subroutines_.find(name) == subroutines_.end()) {//如果子程序已经存在,它们不会添加。
// a new subroutine // a new subroutine
current_subroutine_ = name; current_subroutine_ = name;//设立新名字
Subroutine* routine = new Subroutine(name, description); Subroutine* routine = new Subroutine(name, description);//新建一个子程序。
subroutines_.insert({current_subroutine_, routine}); subroutines_.insert({current_subroutine_, routine});//添加一个新的子程序。
} }
return *this; return *this;
} }
std::map<std::string, std::string> Generator::get_subroutine_list() { std::map<std::string, std::string> Generator::get_subroutine_list() {//是一个成员函数,它返回一个包含所有子程序名称和描述的映射。
std::map<std::string, std::string> kv; std::map<std::string, std::string> kv;
for (auto pr : subroutines_) { for (auto pr : subroutines_) {//遍历所有的子程序
Subroutine* subroutine = pr.second; Subroutine* subroutine = pr.second;//遍历所有的子程序
if (subroutine->get_name() != Subroutine::get_default_name()) if (subroutine->get_name() != Subroutine::get_default_name())//如果子程序的名称不是默认名称
kv[subroutine->get_name()] = subroutine->get_description(); 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, bool Generator::add_usage_line(const char* option, const char* default_value,
const char* description) { const char* description) {// 是一个成员函数,它添加一个使用行到当前子程序。
std::string option_str(option); std::string option_str(option);
auto delimiter_pos = option_str.find(kDelimiter); auto delimiter_pos = option_str.find(kDelimiter);
//定义新变量,将选项字符串赋给新变量
std::string option_short; std::string option_short;
std::string option_long; std::string option_long;
//将选项字符串分割为短选项和长选项
if (delimiter_pos != std::string::npos) { if (delimiter_pos != std::string::npos) {
option_short.assign(std::move(option_str.substr(0, delimiter_pos))); option_short.assign(std::move(option_str.substr(0, delimiter_pos)));
option_long.assign(std::move(option_str.substr(delimiter_pos + 1))); option_long.assign(std::move(option_str.substr(delimiter_pos + 1)));
Row row; Row row;//创建一个Row对象
row.oshort(option_short); row.oshort(option_short);
row.olong(option_long); row.olong(option_long);
row.value(default_value); row.value(default_value);
row.desc(description); row.desc(description);
////设置其短选项、长选项、默认值和描述
get_subroutine()->add_usage_line(row); get_subroutine()->add_usage_line(row);//将这个Row对象添加到当前子程序的使用行中。
return true; return true;
} }
return false; return false;
} }
std::ostream& operator<<(std::ostream& out, Generator& generator) { std::ostream& operator<<(std::ostream& out, Generator& generator) {// 是一个输出运算符重载函数,它打印所有子程序的名称和描述。
for (auto pr : generator.subroutines_) { for (auto pr : generator.subroutines_) {//遍历所有的子程序
Subroutine* subroutine = pr.second; Subroutine* subroutine = pr.second;
if (subroutine->get_name() != Subroutine::get_default_name()) { if (subroutine->get_name() != Subroutine::get_default_name()) {
out << subroutine->get_name() << "\t"; out << subroutine->get_name() << "\t";
}//如果子程序的名称不是默认名称,就打印子程序的名称
out << subroutine->get_description();//打印子程序的描述
if (!subroutine->get_usage().empty()) {//如果子程序的使用信息不为空,就打印一个换行符
out << std::endl;//打印一个换行符
} }
out << subroutine->get_description(); out << *subroutine;//打印子程序的使用信息。
if (!subroutine->get_usage().empty()) {
out << std::endl;
}
out << *subroutine;
} }
return out; return out;
} }
// class ParseItem // 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 // class Parser
ParseItem* Parser::get(const std::string& key) { ParseItem* Parser::get(const std::string& key) {//Parser 类的 get 方法,它接受一个 std::string 类型的参数 key。
if (pr_->find(key) != pr_->end()) { if (pr_->find(key) != pr_->end()) {//如果 key 在 pr_ 中存在
return (*pr_)[key]; 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::~Parser() { this->cleanup(); }
//这是 Parser 类的析构函数,它调用 cleanup 方法来清理资源。
Parser::ParseResult* Parser::parse(const int argc, const char** argv) { Parser::ParseResult* Parser::parse(const int argc, const char** argv) {//Parser 类的 parse 方法,它接受命令行参数的数量 argc 和参数值 argv
if (!this->init(argc, argv)) { if (!this->init(argc, argv)) {//它调用 init 方法来初始化解析过程
return nullptr; return nullptr;//如果初始化失败,那么返回 nullptr
} }
auto ibegin = args_.begin() + 1; // ignore the first cmd name auto ibegin = args_.begin() + 1; // 忽略第一个命令名
auto iend = args_.end(); auto iend = args_.end();
auto it = ibegin; auto it = ibegin;//定义开始变量名
if (argc >= 2 && args_[1][0] != '-') { if (argc >= 2 && args_[1][0] != '-') {
// the second block may be a subroutine name // 第二个块可能是一个子程序名
// e.g., ./exec pull --option // e.g., ./exec pull --option
if (subroutines_ && (subroutines_->find(args_[1]) != subroutines_->end())) { if (subroutines_ && (subroutines_->find(args_[1]) != subroutines_->end())) {
subroutine_name_ = args_[1]; subroutine_name_ = args_[1];
it++; // ignore the subroutine name it++; // 忽略子程序名
} else { } else {
subroutine_name_ = args_[1]; subroutine_name_ = args_[1];
} }
} else { } else {
// there is no options as well as subroutine name // 没有选项以及子程序名
// e.g., ./exec // 例如,./exec
subroutine_name_ = Subroutine::get_default_name(); subroutine_name_ = Subroutine::get_default_name();
} }
std::string block; std::string block;//声明变量
std::string previous(*ibegin); std::string previous(*ibegin);//声明变量
for (; it != iend; ++it) { for (; it != iend; ++it) {// 遍历所有的命令行参数
block.assign(*it); block.assign(*it);// 将当前参数赋值给 block
switch (block.size()) { switch (block.size()) {//// 根据 block 的大小进行不同的处理
case 1: case 1://// 如果 block 的大小为 1
if (block == "-") { if (block == "-") {//// 如果 block 是一个单独的 "-"
throw ParseError("single '-' is not allowed"); throw ParseError("single '-' is not allowed");//// 抛出异常,因为单独的 "-" 是不允许的
} }
break; break;
case 2: case 2:// // 如果 block 的大小为 2
if (block[0] == '-') { if (block[0] == '-') {//// 如果 block 的第一个字符是 "-"
if (block[1] == '-') { if (block[1] == '-') {//// 如果 block 的第二个字符也是 "-"
throw ParseError("option '--' is incomplete"); throw ParseError("option '--' is incomplete");//// 抛出异常,因为 "--" 是不完整的选项
} else if (block[1] == '=') {
throw ParseError("option '-=' is invalid"); } else if (block[1] == '=') {//// 如果 block 的第二个字符是 "="
throw ParseError("option '-=' is invalid");//// 抛出异常,因为 "-=" 是无效的选项
} else { } else {
// single option // 单个选项
// e.g., ./exec -s // e.g., ./exec -s
(*pr_)[block.substr(1)] = nullptr; (*pr_)[block.substr(1)] = nullptr;
} }
} }
break; break;
default: // >=3 default: // >=3
if (block[0] == '-') { if (block[0] == '-') {//// 如果 block 的第一个字符是 "-"
if (block[1] == '-') { if (block[1] == '-') {//// 如果 block 的第二个字符也是 "-"
size_t pos_equal = block.find('='); size_t pos_equal = block.find('=');//// 查找 "=" 在 block 中的位置
if (pos_equal == std::string::npos) { if (pos_equal == std::string::npos) {//// 如果没有找到 "="
// a long format option // 长格式选项
// e.g., ./exec --option // e.g., ./exec --option
(*pr_)[block.substr(2)] = nullptr; (*pr_)[block.substr(2)] = nullptr;//// 将选项添加到 pr_ 中,值为 nullptr
} else { } else {
if (pos_equal > 3) { if (pos_equal > 3) {// 如果 "=" 的位置大于 3
// e.g, ./exec --op[..=]value // e.g, ./exec --op[..=]value
std::string key(block.substr(2, pos_equal - 2)); std::string key(block.substr(2, pos_equal - 2));// 获取选项名
if (block.size() > 5) if (block.size() > 5)//// 如果 block 的大小大于 5
// e.g, ./exec --op=v // 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 else
(*pr_)[key] = nullptr; (*pr_)[key] = nullptr;// 将选项添加到 pr_ 中,值为 nullptr
} else { } else {
// a long format option but = is illegal // 长格式选项但 = 是非法的
// e.g., ./exec --o=[...] // e.g., ./exec --o=[...]
(*pr_)[block.substr(2)] = nullptr; (*pr_)[block.substr(2)] = nullptr;//// 将选项添加到 pr_ 中,值为 nullptr
} }
} }
} else if (block[2] == '=') { } else if (block[2] == '=') {// // 如果 block 的第三个字符是 "="
// a single option with = // 单个选项带有 =
// e.g., ./exec -o=[...] // e.g., ./exec -o=[...]
std::string key; std::string key;
key.push_back(block[1]); key.push_back(block[1]);// 获取选项名
if (block.size() > 3) if (block.size() > 3)// 如果 block 的大小大于 3
(*pr_)[key] = new ParseItem(block.substr(3)); (*pr_)[key] = new ParseItem(block.substr(3));//// 将选项和值添加到 pr_ 中
else else
(*pr_)[key] = nullptr; (*pr_)[key] = nullptr;// 将选项添加到 pr_ 中,值为 nullptr
} else { } else {
// a combination options // 组合选项
// e.g., ./exec -ab[...] // e.g., ./exec -ab[...]
auto tbegin = block.begin() + 1; // ignore the first '-' auto tbegin = block.begin() + 1; // 忽略第一个 '-'
auto tend = block.end(); auto tend = block.end();
auto t = tbegin; auto t = tbegin;
for (; t != tend; ++t) { for (; t != tend; ++t) { // 遍历 block 中的每个字符
std::string key; std::string key;
key.push_back(*t); key.push_back(*t);// // 获取选项名
(*pr_)[key] = nullptr; (*pr_)[key] = nullptr; // 将选项添加到 pr_ 中,值为 nullptr
} }
} }
} }
break; break;
} // switch } // switch
if (block[0] != '-' && previous != block // not the first option if (block[0] != '-' && previous != block // 如果 block 不是选项(不以 "-" 开头)并且不是第一个选项
) { ) {
if (previous[0] != '-') { if (previous[0] != '-') {//// 如果 previous 不是选项
// previous is not an option, error occur // previous 不是一个选项,发生错误
// e.g., ./exec abc def // e.g., ./exec abc def
throw ParseError("'" + block + "' is not allowed here"); throw ParseError("'" + block + "' is not allowed here");//抛出异常,因为在这里不允许非选项
} }
std::string key; std::string key;
if (previous[0] == '-' && previous[1] == '-') { if (previous[0] == '-' && previous[1] == '-') {//// 如果 previous 是一个长格式选项
// previous is a long format option. // previous is a long format option.
// e.g., ./exec --option value // e.g., ./exec --option value
key = previous.substr(2); key = previous.substr(2);//// 获取选项名
} else { } else {
// it's the value of previous option. // 它是前一个选项的值。
// e.g., ./exec -o [...] // e.g., ./exec -o [...]
// e.g., ./exec -opq [...] // e.g., ./exec -opq [...]
key.push_back(*(previous.end() - 1)); key.push_back(*(previous.end() - 1));// // 获取选项名
} }
if (pr_->find(key) != pr_->end()) { if (pr_->find(key) != pr_->end()) {//// 如果选项在 pr_ 中存在
(*pr_)[key] = new ParseItem(block); (*pr_)[key] = new ParseItem(block); // 将选项和值添加到 pr_ 中
} }
} }
previous = block; previous = block;//// 更新 previous 为当前的 block
} // for } // for
if (subroutines_) { if (subroutines_) {
this->set_addition(); this->set_addition();// 如果存在子程序,调用 set_addition 方法处理额外的选项
} }
return pr_; return pr_;//返回解析结果 pr_
} }
Parser::ParseResult* Parser::parse(const char* command_line) { Parser::ParseResult* Parser::parse(const char* command_line) {//Parser 类的 parse 方法
int i = 0; int i = 0;//初始化计数器
std::string block; std::string block;//用于存储单个命令行参数
std::vector<std::string> blocks; std::vector<std::string> blocks;//声明用于存储所有命令行参数
char c; char c;//声明用于存储当前字符
while ((c = command_line[i++]) != '\0') { while ((c = command_line[i++]) != '\0') {// 遍历命令行字符串
if (c != ' ') { if (c != ' ') {// 如果当前字符不是空格
block.push_back(c); block.push_back(c);//// 将当前字符添加到 block
} else { } else {
if (!block.empty()) { if (!block.empty()) {// 如果 block 不为空
blocks.push_back(block); blocks.push_back(block);// 将 block 添加到 blocks
} }
block.clear(); block.clear();//清空 block
} }
} }
if (!block.empty()) { if (!block.empty()) {// 如果最后一个 block 不为空
blocks.push_back(block); blocks.push_back(block);// 将 block 添加到 blocks
} }
size_t size = blocks.size(); // argc size_t size = blocks.size(); // argc
char** argv = new char*[size]; char** argv = new char*[size];// 创建一个新的 char* 数组
i = 0; i = 0;
std::for_each(blocks.begin(), blocks.end(), [argv, &i](const std::string& b) { std::for_each(blocks.begin(), blocks.end(), [argv, &i](const std::string& b) {// 遍历 blocks
argv[i++] = const_cast<char*>(b.c_str()); argv[i++] = const_cast<char*>(b.c_str());// 将每个 block 转换为 char* 并存储在 argv 中
}); });
auto pr = auto pr =
this->parse(static_cast<const int>(size), const_cast<const char**>(argv)); this->parse(static_cast<const int>(size), const_cast<const char**>(argv)); // 调用 parse 方法解析命令行参数
delete[] argv; delete[] argv;// 删除 argv
argv = nullptr; argv = nullptr;
return pr; return pr;// 返回解析结果
} }
bool Parser::has(const char* key) { bool Parser::has(const char* key) {//Parser 类的 has 方法,它接受一个 char 指针 key并检查 key 是否在 pr_ 中存在。
std::string skey(key); std::string skey(key);// 将 key 转换为 std::string
if (pr_ && !pr_->empty() && !skey.empty()) { if (pr_ && !pr_->empty() && !skey.empty()) {//判断是否存在
if (skey[0] == '-') { if (skey[0] == '-') {
// check combination options, e.g., Parser::has("-xyz") // 如果 skey 是一个组合选项,例如 "-xyz"
for (size_t i = 1; i < skey.size(); ++i) { for (size_t i = 1; i < skey.size(); ++i) {// 遍历 skey 的每个字符
std::string tkey; std::string tkey;
tkey.push_back(skey[i]); tkey.push_back(skey[i]);// 获取选项名
if (pr_->find(tkey) == pr_->end()) { if (pr_->find(tkey) == pr_->end()) { // 如果选项名在 pr_ 中不存在
return false; return false;
} }
} }
return true; return true;
} else { } else {
// check single option, e.g., Parser::has("x") // 如果 skey 是一个单个选项,例如 "x"
return pr_->find(skey) != pr_->end(); 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<const char*> options) { bool Parser::has_or(std::initializer_list<const char*> options) {
if (options.size() == 0) { if (options.size() == 0) {// 如果 options 为空
return false; return false;
}4
for (auto key : options) {// 遍历 options 中的每个选项
if (this->has(key)) return true;// 如果选项在 pr_ 中存在,返回 true
} }
for (auto key : options) { return false;// 如果 options 中的所有选项都不存在,返回 false
if (this->has(key)) return true;
}
return false;
} }
bool Parser::has_and(std::initializer_list<const char*> options) { bool Parser::has_and(std::initializer_list<const char*> options) { // Parser 类的 has_and 方法,接受一个初始化列表 options
if (options.size() == 0) { if (options.size() == 0) {// 如果 options 为空
return false; return false;
} }
for (auto key : options) { for (auto key : options) {// 遍历 options 中的每个选项
if (!this->has(key)) return false; if (!this->has(key)) return false;// 如果选项在 pr_ 中不存在,返回 false
} }
return true; return true;// 如果 options 中的所有选项都存在,返回 true
} }
bool Parser::init(const int argc, const char** argv) { bool Parser::init(const int argc, const char** argv) {
argc_ = argc; argc_ = argc;// 保存参数数量
// argv_ = argv; // argv_ = argv;
// don't save it, point to a local var in parse(const char* command_line). // don't save it, point to a local var in parse(const char* command_line).
// use member var args_ instead. // use member var args_ instead.
if (argc > 0) { if (argc > 0) {// 如果参数数量大于 0
this->cleanup(); this->cleanup(); // 清理之前的解析结果
args_.reserve(static_cast<size_t>(argc_)); args_.reserve(static_cast<size_t>(argc_));// 为 args_ 预留空间
for (int i = 0; i < argc_; ++i) { for (int i = 0; i < argc_; ++i) {// 遍历所有的命令行参数
args_.push_back(argv[i]); args_.push_back(argv[i]);// 将参数添加到 args_
} }
pr_ = new Parser::ParseResult; pr_ = new Parser::ParseResult;// 创建新的解析结果
return true; return true;
} }
return false; return false;// 如果参数数量为 0返回 false
} }
void Parser::cleanup() { void Parser::cleanup() {// Parser 类的 cleanup 方法,用于清理解析结果
args_.clear(); args_.clear();// 清空 args_
if (pr_) { if (pr_) {// 如果 pr_ 不为空
auto ibegin = pr_->begin(); auto ibegin = pr_->begin();
auto iend = pr_->end(); auto iend = pr_->end();
auto it = ibegin; auto it = ibegin;
for (; it != iend; ++it) { for (; it != iend; ++it) {// 遍历 pr_ 中的每个元素
ParseItem* item = it->second; ParseItem* item = it->second;
if (item) delete item; if (item) delete item;// 删除元素
} }
delete pr_; delete pr_;// 删除 pr_
pr_ = nullptr; pr_ = nullptr;
} }
} }
void Parser::set_addition() { void Parser::set_addition() {// Parser 类的 set_addition 方法,用于处理额外的选项
if (subroutines_->find(subroutine_name_) != subroutines_->end()) { if (subroutines_->find(subroutine_name_) != subroutines_->end()) {// 如果子程序名在 subroutines_ 中存在
for (const Row& row : *(subroutines_->at(subroutine_name_))) { for (const Row& row : *(subroutines_->at(subroutine_name_))) {// 遍历子程序中的每一行
// assume both -o and --option are allowed, // assume both -o and --option are allowed,
// but only provide -o, // but only provide -o,
// then set the another --option. // then set the another --option.
// vice versa. // vice versa.
const std::string& def = row.value(); const std::string& def = row.value();// 获取默认值
const std::string& ops = row.oshort(); const std::string& ops = row.oshort();// 获取短选项
const std::string& opl = row.olong(); const std::string& opl = row.olong();// 获取长选项
ParseResult& pr = *pr_; ParseResult& pr = *pr_; // 获取解析结果
bool has_short = this->has(ops.c_str()); bool has_short = this->has(ops.c_str());// 检查短选项是否存在
bool has_long = this->has(opl.c_str()); bool has_long = this->has(opl.c_str());// 检查长选项是否存在
// assume -o [ --option ] arg = 1 // assume -o [ --option ] arg = 1
// but not provide option value, // but not provide option value,
// then set to default 1. // then set to default 1.
// otherwise, both set to user defined value // otherwise, both set to user defined value
if (!ops.empty()) { if (!ops.empty()) {// 如果短选项不为空
if (has_short) { if (has_short) {// 如果短选项存在
if (pr[ops] != nullptr && !opl.empty()) { if (pr[ops] != nullptr && !opl.empty()) {// 如果短选项有值且长选项不为空
pr[opl] = new ParseItem(std::move(pr[ops]->val())); pr[opl] = new ParseItem(std::move(pr[ops]->val()));// 将短选项的值赋给长选项
} else if (pr[ops] == nullptr && !def.empty()) { } else if (pr[ops] == nullptr && !def.empty()) {// 如果短选项没有值且默认值不为空
pr[ops] = new ParseItem(std::move(def)); pr[ops] = new ParseItem(std::move(def));// 将默认值赋给短选项
if (!opl.empty()) pr[opl] = new ParseItem(std::move(def)); if (!opl.empty()) pr[opl] = new ParseItem(std::move(def));// 如果长选项不为空,也将默认值赋给长选项
} else { } else {
pr[opl] = nullptr; pr[opl] = nullptr;// 将长选项的值设为 nullptr
} }
} }
} }
if (!opl.empty()) { if (!opl.empty()) {// 如果长选项不为空
if (has_long) { if (has_long) { // 如果长选项存在
if (pr[opl] != nullptr && !ops.empty()) { if (pr[opl] != nullptr && !ops.empty()) { // 如果长选项有值且短选项不为空
pr[ops] = new ParseItem(std::move(pr[opl]->val())); pr[ops] = new ParseItem(std::move(pr[opl]->val()));// 将长选项的值赋给短选项
} else if (pr[opl] == nullptr && !def.empty()) { } else if (pr[opl] == nullptr && !def.empty()) {// 如果长选项没有值且默认值不为空
if (!ops.empty()) pr[ops] = new ParseItem(std::move(def)); if (!ops.empty()) pr[ops] = new ParseItem(std::move(def));// 如果短选项不为空,将默认值赋给短选项
pr[opl] = new ParseItem(std::move(def)); pr[opl] = new ParseItem(std::move(def));// 将默认值赋给长选项
} else { } else {
pr[ops] = nullptr; pr[ops] = nullptr;// 将短选项的值设为 nullptr
} }
} }
} }
if (!has_long && !has_short && !def.empty()) { if (!has_long && !has_short && !def.empty()) {// 如果长选项和短选项都不存在且默认值不为
if (!opl.empty()) pr[opl] = new ParseItem(std::move(def)); if (!opl.empty()) pr[opl] = new ParseItem(std::move(def));// 如果长选项不为空,将默认值赋给长选项
if (!ops.empty()) pr[ops] = new ParseItem(std::move(def)); if (!ops.empty()) pr[ops] = new ParseItem(std::move(def));// 如果短选项不为空,将默认值赋给短选项
} }
} // for } // for
} // if } // if
@ -427,114 +433,115 @@ void Parser::set_addition() {
// class Row // class Row
Row::Row() : require_value(true) {} Row::Row() : require_value(true) {} // Row 类的构造函数,初始化 require_value 为 true
// class Subroutine // class Subroutine
Subroutine::Subroutine() : first_line_("") {} Subroutine::Subroutine() : first_line_("") {}// Subroutine 类的默认构造函数,初始化 first_line_ 为空字符串
Subroutine::Subroutine(const char* name, const char* description) Subroutine::Subroutine(const char* name, const char* description)
: first_line_(""), description_(description), name_(name) { : first_line_(""), description_(description), name_(name) { // Subroutine 类的构造函数,接受子程序名和描述作为参数
usages_.reserve(5); 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 // 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 // print the first line
out << get_first_line(); out << get_first_line();
if (!usages_.empty()) { if (!usages_.empty()) {// 如果 usages_ 不为空
out << std::endl; out << std::endl;// 打印换行符
} }
} }
auto begin = usages_.begin(); auto begin = usages_.begin(); // 获取 usages_ 的开始迭代器
auto end = usages_.end(); auto end = usages_.end();// 获取 usages_ 的结束迭代器
std::vector<std::string> row_list; std::vector<std::string> row_list;// 创建一个字符串向量用于存储行
row_list.reserve(usages_.size()); row_list.reserve(usages_.size());// 为 row_list 预留空间
// build usage rows without description field, // build usage rows without description field,
// find the max-len row at the same time. // find the max-len row at the same time.
size_t max_len = 0; size_t max_len = 0;
std::for_each(begin, end, [&max_len, &row_list](const Row& row) { std::for_each(begin, end, [&max_len, &row_list](const Row& row) {// 遍历 usages_
std::stringstream ss; std::stringstream ss;// 创建一个字符串流
ss << " "; ss << " ";// 向字符串流中添加两个空格
if (!row.oshort().empty()) { if (!row.oshort().empty()) {// 如果短选项不为空
ss << "-" << row.oshort() << " "; ss << "-" << row.oshort() << " "; // 添加短选项
} }
if (!row.olong().empty()) { if (!row.olong().empty()) {// 如果长选项不为空
if (!row.oshort().empty()) if (!row.oshort().empty())
ss << "[ --" << row.olong() << " ] "; ss << "[ --" << row.olong() << " ] ";// 添加长选项
else else
ss << "--" << row.olong() << " "; ss << "--" << row.olong() << " "; // 添加长选项
} }
if (row.required()) { if (row.required()) {// 如果选项是必需的
ss << "arg "; ss << "arg "; // 添加 "arg "
if (!row.value().empty()) { if (!row.value().empty()) {// 如果选项值不为空
ss << "= " << row.value() << " "; ss << "= " << row.value() << " ";// 添加选项值
} }
} }
max_len = std::max(max_len, ss.str().size()); max_len = std::max(max_len, ss.str().size());// 更新最大长度
row_list.push_back(std::move(ss.str())); row_list.push_back(std::move(ss.str()));// 将字符串流的内容添加到 row_list
}); });
// show all rows and align description field // show all rows and align description field
size_t row_count = usages_.size(); size_t row_count = usages_.size();// 获取 usages_ 的大小
for (size_t i = 0; i < row_count; ++i) { for (size_t i = 0; i < row_count; ++i) {// 遍历 usages_
std::string str_row(std::move(row_list[i])); std::string str_row(std::move(row_list[i]));// 获取当前行
// print row without description // print row without description
out << str_row; out << str_row;// 打印当前行
// print spaces // print spaces
size_t spaces = 0; size_t spaces = 0;// 打印空格
size_t len = str_row.size(); size_t len = str_row.size();// 获取当前行的长度
if (max_len > len) spaces = max_len - len; if (max_len > len) spaces = max_len - len;// 计算需要打印的空格数量
while (spaces--) { while (spaces--) {// 打印空格
out << " "; out << " ";
} }
// print description // print description
out << usages_.at(i).desc() << std::endl; out << usages_.at(i).desc() << std::endl;// 打印描述
} }
} }
void Subroutine::print_with_template(std::ostream& out) { void Subroutine::print_with_template(std::ostream& out) {// Subroutine 类的 print_with_template 方法,接受一个输出流作为参数
for (auto usage : usages_) { for (auto usage : usages_) {// 遍历 usages_
size_t i = 0; size_t i = 0;
for (auto t = template_str_.begin(); t != template_str_.end(); ++t) { for (auto t = template_str_.begin(); t != template_str_.end(); ++t) {// 遍历模板字符串
if (*t == '%') { if (*t == '%') {// 如果当前字符是 '%'
switch (*(order_.begin() + i)) { switch (*(order_.begin() + i)) { // 根据 order_ 中的值决定打印哪个字段
case Row::kShort: case Row::kShort:
out << usage.oshort(); out << usage.oshort();// 打印短选项
break; break;
case Row::kLong: case Row::kLong:
out << usage.olong(); out << usage.olong();// 打印长选项
break; break;
case Row::kDefault: case Row::kDefault:
out << usage.value(); out << usage.value();// 打印默认值
break; break;
case Row::kDescription: case Row::kDescription:
out << usage.desc(); out << usage.desc();// 打印描述
break; break;
default: default:
break; break;
} }
++i; ++i;
} else { } else {
out << *t; out << *t;// 如果当前字符不是 '%',直接打印
} // if % } // if %
} // for template_str_ } // for template_str_
out << std::endl; out << std::endl;// 打印换行符
} // for usages_ } // for usages_
} }
std::ostream& operator<<(std::ostream& out, Subroutine& subroutine) { std::ostream& operator<<(std::ostream& out, Subroutine& subroutine) {// 重载 << 运算符,接受一个输出流和一个 Subroutine 对象作为参数
if (subroutine.template_str_.empty()) { if (subroutine.template_str_.empty()) {// 如果模板字符串为空
subroutine.print_with_row(out); subroutine.print_with_row(out);// 使用 print_with_row 方法打印
} else { } else {
subroutine.print_with_template(out); subroutine.print_with_template(out);// 使用 print_with_template 方法打印
} }
return out; return out;// 返回输出流
} }
} }

@ -1,127 +1,127 @@
#include "easypr/util/util.h" #include "easypr/util/util.h"
#include <string> #include <string>
#ifdef OS_WINDOWS // #ifdef OS_WINDOWS
#include <windows.h> #include <windows.h> // 包含windows.h头文件用于Windows平台的系统调用
#include <direct.h> #include <direct.h> // 包含direct.h头文件用于Windows平台的目录操作
#include <io.h> #include <io.h> // 包含io.h头文件用于Windows平台的IO操作
#define PATH_DELIMITER '\\' #define PATH_DELIMITER '\\' // 定义路径分隔符为'\\'
#ifdef min #ifdef min
#undef min #undef min // 如果已经定义了min取消其定义
#endif #endif
#ifdef max #ifdef max
#undef max #undef max // 如果已经定义了max取消其定义
#endif #endif
#elif defined(OS_LINUX) || defined(OS_UNIX) #elif defined(OS_LINUX) || defined(OS_UNIX)
#include <cstring> #include <cstring> // 包含cstring头文件用于字符串操作
#include <dirent.h> #include <dirent.h> // 包含dirent.h头文件用于目录操作
#include <sys/stat.h> #include <sys/stat.h> // 包含sys/stat.h头文件用于文件状态检查
#include <unistd.h> #include <unistd.h> // 包含unistd.h头文件用于Unix标准的系统调用
#define PATH_DELIMITER '/' #define PATH_DELIMITER '/' // 定义路径分隔符为'/'
#endif #endif
#ifdef OS_UNIX #ifdef OS_UNIX
#include <sys/timeb.h> #include <sys/timeb.h> // 包含sys/timeb.h头文件用于时间操作
#endif #endif
#include <list> #include <list> // 包含list头文件用于list数据结构
#include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui.hpp> // 包含opencv的highgui模块用于图像IO操作
namespace easypr { namespace easypr { // 定义easypr命名空间
long Utils::getTimestamp() { long Utils::getTimestamp() { // 定义获取时间戳的函数
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
return static_cast<long>(cv::getTickCount()); return static_cast<long>(cv::getTickCount()); // Windows平台下使用opencv的getTickCount函数获取时间戳
#endif #endif
#ifdef OS_LINUX #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 #endif
#ifdef OS_UNIX #ifdef OS_UNIX
// there is no function provided by osx to get system tick count. // there is no function provided by osx to get system tick count.
// but considering the purpose by using this function, // but considering the purpose by using this function,
// we can simply return a millisecond since 1970/1/1 to calc the time elapse. // we can simply return a millisecond since 1970/1/1 to calc the time elapse.
struct timeb tb; struct timeb tb; // 定义timeb结构体用于获取时间
ftime(&tb); ftime(&tb); // 获取当前时间
return long(tb.time * 1e3 + tb.millitm); return long(tb.time * 1e3 + tb.millitm); // 返回毫秒级的时间戳
#endif #endif
} }
std::string Utils::getFileName(const std::string &path, std::string Utils::getFileName(const std::string &path,
const bool postfix /* = false */) { const bool postfix /* = false */) { // 定义获取文件名的函数
if (!path.empty()) { if (!path.empty()) { // 如果路径不为空
size_t last_slash = utils::get_last_slash(path); size_t last_slash = utils::get_last_slash(path); // 获取路径中最后一个斜杠的位置
size_t last_dot = path.find_last_of('.'); size_t last_dot = path.find_last_of('.'); // 获取路径中最后一个点的位置
if (last_dot < last_slash || last_dot == std::string::npos) { if (last_dot < last_slash || last_dot == std::string::npos) {
// not found the right dot of the postfix, // not found the right dot of the postfix,
// return the file name directly // return the file name directly
return path.substr(last_slash + 1); return path.substr(last_slash + 1); // 如果没有找到正确的后缀点,直接返回文件名
} else { } else {
// the path has a postfix // the path has a postfix
if (postfix) { if (postfix) {
// return the file name including postfix // return the file name including postfix
return path.substr(last_slash + 1); return path.substr(last_slash + 1); // 如果路径有后缀,并且需要返回后缀,返回包含后缀的文件名
} }
// without postfix // 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<std::string> Utils::splitString(const std::string &str, std::vector<std::string> Utils::splitString(const std::string &str,
const char delimiter) { const char delimiter) { // 定义字符串分割函数
std::vector<std::string> splited; std::vector<std::string> splited; // 定义存储分割结果的vector
std::string s(str); std::string s(str); // 复制输入的字符串
size_t pos; size_t pos; // 定义分割位置
while ((pos = s.find(delimiter)) != std::string::npos) { while ((pos = s.find(delimiter)) != std::string::npos) { // 当找到分隔符时
std::string sec = s.substr(0, pos); std::string sec = s.substr(0, pos); // 获取分隔符前的子串
if (!sec.empty()) { if (!sec.empty()) { // 如果子串不为空
splited.push_back(s.substr(0, pos)); 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<std::string> Utils::getFiles(const std::string &folder, std::vector<std::string> Utils::getFiles(const std::string &folder,
const bool all /* = true */) { const bool all /* = true */) { // 定义获取文件列表的函数
std::vector<std::string> files; std::vector<std::string> files; // 定义存储文件列表的vector
std::list<std::string> subfolders; std::list<std::string> subfolders; // 定义存储子文件夹的list
subfolders.push_back(folder); subfolders.push_back(folder); // 将输入的文件夹添加到子文件夹列表中
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
while (!subfolders.empty()) { while (!subfolders.empty()) { // 当子文件夹列表不为空时
std::string current_folder(subfolders.back()); std::string current_folder(subfolders.back()); // 获取当前处理的文件夹
if (*(current_folder.end() - 1) != '/') { if (*(current_folder.end() - 1) != '/') {
current_folder.append("/*"); current_folder.append("/*"); // 如果当前文件夹的路径不以'/'结尾,添加'/*'
} else { } else {
current_folder.append("*"); current_folder.append("*"); // 如果当前文件夹的路径以'/'结尾,添加'*'
} }
subfolders.pop_back(); subfolders.pop_back(); // 从子文件夹列表中移除当前处理的文件夹
struct _finddata_t file_info; struct _finddata_t file_info; // 定义文件信息结构体
auto file_handler = _findfirst(current_folder.c_str(), &file_info); auto file_handler = _findfirst(current_folder.c_str(), &file_info); // 打开当前文件夹
while (file_handler != -1) { while (file_handler != -1) { // 当文件夹打开成功时
if (all && if (all &&
(!strcmp(file_info.name, ".") || !strcmp(file_info.name, ".."))) { (!strcmp(file_info.name, ".") || !strcmp(file_info.name, ".."))) {
if (_findnext(file_handler, &file_info) != 0) break; if (_findnext(file_handler, &file_info) != 0) break;
@ -136,7 +136,7 @@ std::vector<std::string> Utils::getFiles(const std::string &folder,
folder.pop_back(); folder.pop_back();
folder.append(file_info.name); folder.append(file_info.name);
subfolders.push_back(folder.c_str()); subfolders.push_back(folder.c_str()); // 如果是子文件夹,并且需要搜索子文件夹,将子文件夹添加到子文件夹列表中
} }
} else { } else {
// it's a file // it's a file
@ -145,24 +145,24 @@ std::vector<std::string> Utils::getFiles(const std::string &folder,
file_path.assign(current_folder.c_str()).pop_back(); file_path.assign(current_folder.c_str()).pop_back();
file_path.append(file_info.name); file_path.append(file_info.name);
files.push_back(file_path); files.push_back(file_path); // 如果是文件,将文件路径添加到文件列表中
} }
if (_findnext(file_handler, &file_info) != 0) break; if (_findnext(file_handler, &file_info) != 0) break;
} // while } // while
_findclose(file_handler); _findclose(file_handler); // 关闭文件夹
} }
#elif defined(OS_LINUX) || defined(OS_UNIX) #elif defined(OS_LINUX) || defined(OS_UNIX)
while (!subfolders.empty()) { while (!subfolders.empty()) { // 当子文件夹列表不为空时
std::string current_folder(subfolders.back()); std::string current_folder(subfolders.back()); // 获取当前处理的文件夹
if (*(current_folder.end() - 1) != '/') { 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) { if (!pdir) {
continue; continue;
@ -170,9 +170,9 @@ std::vector<std::string> Utils::getFiles(const std::string &folder,
dirent* dir = NULL; dirent* dir = NULL;
while ((dir = readdir(pdir)) != NULL) { while ((dir = readdir(pdir)) != NULL) { // 当读取到文件或文件夹时
// iterates the current folder, search file & sub folder // iterates the current folder, search file & sub folder
struct stat st; struct stat st; // 定义文件状态结构体
if (all && (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))) { if (all && (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))) {
// must ignore . & .. // must ignore . & ..
@ -201,93 +201,93 @@ std::vector<std::string> Utils::getFiles(const std::string &folder,
std::string subfolder(current_folder); std::string subfolder(current_folder);
subfolder.append(dir->d_name); subfolder.append(dir->d_name);
subfolders.push_back(subfolder.c_str()); subfolders.push_back(subfolder.c_str()); // 如果是子文件夹,并且需要搜索子文件夹,将子文件夹添加到子文件夹列表中
} }
} else { } else {
// it's a file // it's a file
files.push_back(file_path); files.push_back(file_path); // 如果是文件,将文件路径添加到文件列表中
} }
} // while } // while
closedir(pdir); closedir(pdir); // 关闭文件夹
} }
#endif #endif
return files; return files; // 返回文件列表
} }
bool Utils::mkdir(const std::string folder) { bool Utils::mkdir(const std::string folder) { // 定义创建文件夹的函数
std::string folder_builder; std::string folder_builder; // 定义文件夹路径构造器
std::string sub; std::string sub; // 定义子路径
sub.reserve(folder.size()); 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; const char c = *it;
sub.push_back(c); sub.push_back(c);
if (c == PATH_DELIMITER || it == folder.end() - 1) { if (c == PATH_DELIMITER || it == folder.end() - 1) { // 当遇到路径分隔符或路径结束时
folder_builder.append(sub); folder_builder.append(sub); // 将子路径添加到文件夹路径构造器中
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
if (0 != ::_access(folder_builder.c_str(), 0)) { if (0 != ::_access(folder_builder.c_str(), 0)) { // 如果文件夹不存在
#else #else
if (0 != ::access(folder_builder.c_str(), 0)) { if (0 != ::access(folder_builder.c_str(), 0)) { // 如果文件夹不存在
#endif #endif
// this folder not exist // this folder not exist
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
if (0 != ::_mkdir(folder_builder.c_str())) { if (0 != ::_mkdir(folder_builder.c_str())) { // 如果创建文件夹失败
#else #else
if (0 != ::mkdir(folder_builder.c_str(), S_IRWXU)) { if (0 != ::mkdir(folder_builder.c_str(), S_IRWXU)) { // 如果创建文件夹失败
#endif #endif
// create failed // 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) { bool Utils::imwrite(const std::string &file, const cv::Mat &image) { // 定义图像写入函数
auto folder = file.substr(0, utils::get_last_slash(file)); auto folder = file.substr(0, utils::get_last_slash(file)); // 获取文件所在的文件夹
Utils::mkdir(folder); Utils::mkdir(folder); // 创建文件所在的文件夹
return cv::imwrite(file, image); return cv::imwrite(file, image); // 写入图像
} }
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
std::string Utils::utf8_to_gbk(const char* utf8) { std::string Utils::utf8_to_gbk(const char* utf8) { // 定义UTF-8到GBK的转换函数
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); // 获取转换后的长度
wchar_t* wszGBK = new wchar_t[len + 1]; wchar_t* wszGBK = new wchar_t[len + 1]; // 定义存储转换结果的宽字符数组
memset(wszGBK, 0, len * 2 + 2); memset(wszGBK, 0, len * 2 + 2); // 初始化宽字符数组
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wszGBK, len); MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wszGBK, len); // 将UTF-8字符串转换为宽字符字符串
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); // 获取转换后的长度
char* szGBK = new char[len + 1]; char* szGBK = new char[len + 1]; // 定义存储转换结果的字符数组
memset(szGBK, 0, len + 1); memset(szGBK, 0, len + 1); // 初始化字符数组
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); // 将宽字符字符串转换为GBK字符串
std::string strTemp(szGBK); std::string strTemp(szGBK); // 将GBK字符串转换为std::string
if (wszGBK) if (wszGBK)
delete[] wszGBK; delete[] wszGBK; // 删除宽字符数组
if (szGBK) if (szGBK)
delete[] szGBK; delete[] szGBK; // 删除字符数组
return strTemp; return strTemp; // 返回转换结果
} }
#endif #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 #ifdef OS_WINDOWS
size_t last_slash_1 = 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_2 = path.find_last_of("/"); // 获取路径中最后一个'/'的位置
size_t last_slash; size_t last_slash;
if (last_slash_1 != std::string::npos && last_slash_2 != std::string::npos) { if (last_slash_1 != std::string::npos && last_slash_2 != std::string::npos) {
// C:/path\\to/file.postfix // 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 { } else {
// C:\\path\\to\\file.postfix // C:\\path\\to\\file.postfix
// C:/path/to/file.postfix // C:/path/to/file.postfix
last_slash = 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 #else
size_t last_slash = path.find_last_of('/'); size_t last_slash = path.find_last_of('/'); // 获取路径中最后一个'/'的位置
#endif #endif
return last_slash; return last_slash; // 返回最后一个斜杠的位置
} }
} // namespace easypr } // namespace easypr
Loading…
Cancel
Save