335 lines
11 KiB
C++
335 lines
11 KiB
C++
#ifndef UTIL_H
|
||
#define UTIL_H
|
||
|
||
#include <sstream>
|
||
#include <iomanip>
|
||
#include <vector>
|
||
#include "pugixml.hpp"
|
||
#include "nlohmann/json.hpp"
|
||
#include <QString>
|
||
#include <QDateTime>
|
||
#include <QSet>
|
||
using json = nlohmann::json;
|
||
|
||
// 宏定义:销毁指针
|
||
#define DELETE_PTR(p) \
|
||
if (p) \
|
||
{ \
|
||
delete p; \
|
||
p = nullptr; \
|
||
}
|
||
#define DELETE_PTR_LIST(list) \
|
||
{ \
|
||
for (auto x : list) \
|
||
delete x; \
|
||
list.clear(); \
|
||
}
|
||
|
||
// 显示类型转换
|
||
#define ST_C_DOUBLE static_cast<double>
|
||
|
||
// mdb转db,bool类型转为TEXT类型的对应关系
|
||
#define MDB_BOOL2DB_TEXT(value) ((value) ? "Y" : "N")
|
||
#define DB_TEXT2MDB_BOOL(value) (((value) == "Y" || (value) == "1") ? true : false)
|
||
|
||
// db为保持原有mdb中bool转num时的转换关系,需作以下处理
|
||
// 当 Visual Basic 将数值数据类型值转换为 Boolean 时,0 变为 False,所有其他值变为 True,实际VB代码中主要使用-1来转换成True
|
||
#define MDB_NUM2DB_TEXT(value) ((value) == 0 ? "N" : "Y")
|
||
// 当 Visual Basic 将 Boolean 值转换为数值类型时,False 变为 0,True 变为 -1
|
||
#define DB_TEXT2MDB_NUM(value) (((value) == "Y" || (value) == "1") ? -1 : 0)
|
||
|
||
#define MDB_NUM2MDB_BOOL(value) DB_TEXT2MDB_BOOL(MDB_NUM2DB_TEXT(value))
|
||
#define MDB_BOOL2MDB_NUM(value) DB_TEXT2MDB_NUM(MDB_BOOL2DB_TEXT(value)) // mdb默认使用-1 代表true,但其实只要是非0,就都能代表true
|
||
|
||
// 获取Json的键值,存入模板类型变量中
|
||
template <typename ResultType, typename ValueTypeCV>
|
||
static bool JValue_2_TData(ResultType &result, const json &jsonObj, std::string key)
|
||
{
|
||
if (!jsonObj.contains(key.c_str()))
|
||
return false;
|
||
|
||
if constexpr (!std::is_same_v<ValueTypeCV, std::string>)
|
||
result = jsonObj[key.c_str()].get<ValueTypeCV>();
|
||
else
|
||
result = jsonObj[key.c_str()].get<std::string>().c_str();
|
||
|
||
return true;
|
||
};
|
||
|
||
// 能保证float变量转换位double后,float变量全部位数(double的前8位精度)
|
||
// 适合只需要保证double的前8位精度相等的情况
|
||
// 如 float_To_Double_8Dgit(0.12345678f) == 0.12345678
|
||
static double float_To_Double_8Dgit(float fValue)
|
||
{
|
||
std::ostringstream oss;
|
||
oss << std::setprecision(8) << fValue;
|
||
return std::stod(oss.str());
|
||
};
|
||
|
||
// 获取一维数组总长度
|
||
template <typename T>
|
||
static int stdVectorLength(std::vector<T> &vec)
|
||
{
|
||
return vec.size();
|
||
};
|
||
|
||
// 获取二维数组总长度
|
||
template <typename T>
|
||
static int stdVectorLength(std::vector<std::vector<T>> &vec)
|
||
{
|
||
int size = 0;
|
||
for (int i = 0; i < vec.size(); ++i)
|
||
size += static_cast<int>(vec[i].size());
|
||
|
||
return size;
|
||
};
|
||
|
||
// 解析xml元素值
|
||
// 解析xml元素值
|
||
template <typename T>
|
||
T node_to_value(pugi::xml_node node)
|
||
{
|
||
QString qsType;
|
||
if (node.attribute("Type").empty())
|
||
qsType = "System.Int32[]";
|
||
else
|
||
{
|
||
qsType = QString::fromStdString(node.attribute("Type").as_string());
|
||
}
|
||
|
||
// 输出
|
||
if (!node.attribute("Value").empty())
|
||
{
|
||
// 单个值
|
||
pugi::xml_attribute attr = node.attribute("Value");
|
||
|
||
if (qsType == "System.Int32")
|
||
{
|
||
if constexpr ((std::is_same_v<T, int>))
|
||
return attr.as_int();
|
||
else // 数据类型与模板类型不一致就返回模板类型默认值
|
||
return T();
|
||
}
|
||
else if (qsType == "System.Double")
|
||
{
|
||
if constexpr ((std::is_same_v<T, double>))
|
||
return attr.as_double();
|
||
else // 数据类型与模板类型不一致就返回模板类型默认值
|
||
return T();
|
||
}
|
||
else if (qsType == "System.Boolean")
|
||
{
|
||
if constexpr (std::is_same_v<T, bool>)
|
||
return attr.as_bool();
|
||
else // 数据类型与模板类型不一致就返回模板类型默认值
|
||
return T();
|
||
}
|
||
else if (qsType == "System.String")
|
||
{
|
||
if constexpr (std::is_same_v<T, QString>)
|
||
return QString::fromStdString(attr.as_string());
|
||
else // 数据类型与模板类型不一致就返回模板类型默认值
|
||
return T();
|
||
}
|
||
else if (qsType == "System.DateTime")
|
||
{
|
||
if constexpr (std::is_same_v<T, QDateTime>)
|
||
return QDateTime::fromString(attr.as_string(), "dd/MM/yyyy hh:mm:ss");
|
||
else // 数据类型与模板类型不一致就返回模板类型默认值
|
||
return T();
|
||
}
|
||
}
|
||
else /* if (!node.attribute("Name").empty() && !node.attribute("Length").empty()) */
|
||
{
|
||
// 数组值
|
||
if constexpr (std::is_same_v<T, QVector<int>>)
|
||
{
|
||
if (qsType != "System.Int32[]")
|
||
return T(); // 数据类型与模板类型不一致就返回模板类型默认值
|
||
|
||
T list;
|
||
for (pugi::xml_node value = node.first_child(); value; value = value.next_sibling())
|
||
{
|
||
// int index = value.attribute("Index").as_int();
|
||
// int Val = value.text().as_int();
|
||
// list.insert(value.attribute("Index").as_int(), value.text().as_int())
|
||
int Val = value.text().as_int();
|
||
list.append(Val);
|
||
}
|
||
|
||
return list;
|
||
}
|
||
else if constexpr (std::is_same_v<T, QVector<double>>)
|
||
{
|
||
if (qsType != "System.Double[]")
|
||
return T(); // 数据类型与模板类型不一致就返回模板类型默认值
|
||
|
||
T list;
|
||
for (pugi::xml_node value = node.first_child(); value; value = value.next_sibling())
|
||
{
|
||
// int index = value.attribute("Index").as_int();
|
||
// int Val = value.text().as_double();
|
||
// list.insert(value.attribute("Index").as_int(), value.text().as_double());
|
||
|
||
double Val = value.text().as_double();
|
||
list.append(Val);
|
||
}
|
||
|
||
return list;
|
||
}
|
||
else if constexpr (std::is_same_v<T, QStringList>)
|
||
{
|
||
if (qsType != "System.String[]")
|
||
return T();
|
||
T list;
|
||
for (pugi::xml_node value = node.first_child(); value; value = value.next_sibling())
|
||
{
|
||
QString Val = QString::fromStdString(value.text().as_string());
|
||
list.append(Val);
|
||
}
|
||
|
||
return list;
|
||
}
|
||
else
|
||
return T();
|
||
}
|
||
// else
|
||
// return T();
|
||
};
|
||
|
||
template <typename T>
|
||
pugi::xml_node value_to_node(pugi::xml_node &parent_node,
|
||
const QString &child_node_name,
|
||
const T &child_property_value,
|
||
const QString &child_property_name = "",
|
||
const QString &child_preperty_type = "")
|
||
{
|
||
pugi::xml_node node = parent_node.append_child(child_node_name.toUtf8().constData());
|
||
if (child_node_name == "Field" || child_node_name == "Property")
|
||
{
|
||
node.append_attribute("Name").set_value(child_property_name.toUtf8().constData());
|
||
}
|
||
|
||
// 自动推导类型或使用指定类型
|
||
QString typeStr = child_preperty_type.isEmpty() ? []() -> QString
|
||
{
|
||
if constexpr (std::is_same_v<T, int>)
|
||
return "System.Int32";
|
||
else if constexpr (std::is_same_v<T, double>)
|
||
return "System.Double";
|
||
else if constexpr (std::is_same_v<T, bool>)
|
||
return "System.Boolean";
|
||
else if constexpr (std::is_same_v<T, QString>)
|
||
return "System.String";
|
||
else if constexpr (std::is_same_v<T, QDateTime>)
|
||
return "System.DateTime";
|
||
else if constexpr (std::is_same_v<T, QVector<int>>)
|
||
return "System.Int32[]";
|
||
else if constexpr (std::is_same_v<T, QVector<double>>)
|
||
return "System.Double[]";
|
||
else if constexpr (std::is_same_v<T, QStringList>)
|
||
return "System.String[]";
|
||
else
|
||
return "Unknown";
|
||
}()
|
||
: child_preperty_type;
|
||
|
||
node.append_attribute("Type").set_value(typeStr.toUtf8().constData());
|
||
|
||
// 处理标量值
|
||
if constexpr (!std::is_same_v<T, QVector<int>> &&
|
||
!std::is_same_v<T, QVector<double>> &&
|
||
!std::is_same_v<T, QStringList>)
|
||
{
|
||
if constexpr (std::is_same_v<T, QDateTime>)
|
||
{
|
||
node.append_attribute("Value").set_value(child_property_value.toString("MM/dd/yyyy hh:mm:ss").toUtf8().constData());
|
||
}
|
||
else if constexpr (std::is_same_v<T, QString>)
|
||
{
|
||
node.append_attribute("Value").set_value(child_property_value.toUtf8().constData());
|
||
}
|
||
else if constexpr (std::is_same_v<T, bool>)
|
||
{
|
||
node.append_attribute("Value").set_value(child_property_value ? "true" : "false");
|
||
}
|
||
else
|
||
{
|
||
// 对于数值类型使用QString::number
|
||
node.append_attribute("Value").set_value(QString::number(child_property_value).toUtf8().constData());
|
||
}
|
||
}
|
||
// 处理数组值
|
||
else
|
||
{
|
||
static const QSet<QString> validNames = {
|
||
"Src", "KnotID", "KnotDir", "KnotDirII",
|
||
"KnotAX", "KnotAY", "KnotAZ",
|
||
"KnotAXII", "KnotAYII", "KnotAZII",
|
||
"ProjIKnotX", "ProjIKnotY", "ProjIKnotZ",
|
||
"ProjIIKnotX", "ProjIIKnotY", "ProjIIKnotZ",
|
||
"ProjIKnotDir", "ProjIKnotDirII", "ProjIIKnotDir", "ProjIIKnotDirII",
|
||
"ProjIKnotAX", "ProjIKnotAY", "ProjIKnotAZ",
|
||
"ProjIKnotAXII", "ProjIKnotAYII", "ProjIKnotAZII",
|
||
"ProjIIKnotAX", "ProjIIKnotAY", "ProjIIKnotAZ",
|
||
"ProjIIKnotAXII", "ProjIIKnotAYII", "ProjIIKnotAZII",
|
||
"SolidAddMode", "FCharacterPoints", "LCharacterPoints"
|
||
};
|
||
//兼容旧软件Length
|
||
if (validNames.contains(child_property_name)) {
|
||
node.append_attribute("Length").set_value(256);
|
||
}
|
||
else
|
||
{
|
||
node.append_attribute("Length").set_value(child_property_value.size());
|
||
}
|
||
int index = 0;
|
||
for (const auto &item : child_property_value)
|
||
{
|
||
pugi::xml_node itemNode = node.append_child("Value");
|
||
itemNode.append_attribute("Index").set_value(index++);
|
||
if constexpr (std::is_same_v<decltype(item), const QString &>)
|
||
{
|
||
itemNode.text().set(item.toUtf8().constData());
|
||
}
|
||
else
|
||
{
|
||
itemNode.text().set(QString::number(item).toUtf8().constData());
|
||
}
|
||
}
|
||
}
|
||
|
||
return node;
|
||
};
|
||
|
||
#include <iostream>
|
||
#include <locale>
|
||
#include <codecvt>
|
||
#include <clocale>
|
||
|
||
// 将 UTF-8 字符串转换为 UTF-32(UCS-4)
|
||
static std::u32string utf8_to_utf32(const std::string &utf8_str)
|
||
{
|
||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
|
||
return converter.from_bytes(utf8_str);
|
||
};
|
||
|
||
// 将 UTF-32 字符串转换回 UTF-8
|
||
static std::string utf32_to_utf8(const std::u32string &utf32_str)
|
||
{
|
||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
|
||
return converter.to_bytes(utf32_str);
|
||
};
|
||
|
||
// 检查字符串是否包含任何分隔符
|
||
static bool contains_delimiters(const std::string &str, const std::string &delimiters)
|
||
{
|
||
// 转换为 UTF-32 以便正确处理多字节字符
|
||
std::u32string str32 = utf8_to_utf32(str);
|
||
std::u32string delims32 = utf8_to_utf32(delimiters);
|
||
|
||
return str32.find_first_of(delims32) != std::u32string::npos;
|
||
};
|
||
|
||
#endif // UTIL_H
|