332 lines
5.8 KiB
C++
332 lines
5.8 KiB
C++
#include "dl_string.h"
|
|
|
|
#include <cstdarg>
|
|
#include <cstdio>
|
|
|
|
#include <wcwidth.h>
|
|
|
|
|
|
namespace dl
|
|
{
|
|
std::string to_string(std::error_code code)
|
|
{
|
|
return fmt::format("{}({}): {}",
|
|
code.category().name(),
|
|
code.value(),
|
|
CodeCvt::MultiByteToUtf8(code.message()));
|
|
}
|
|
|
|
std::string to_string(std::exception& e)
|
|
{
|
|
return CodeCvt::MultiByteToUtf8(e.what());
|
|
}
|
|
|
|
namespace String
|
|
{
|
|
std::string Sprintf(const char* format, ...)
|
|
{
|
|
va_list args;
|
|
int len;
|
|
|
|
va_start(args, format);
|
|
len = vsnprintf(nullptr, 0, format, args) + 1;
|
|
va_end(args);
|
|
|
|
std::string ret;
|
|
ret.resize(len);
|
|
|
|
va_start(args, format);
|
|
vsnprintf((char*)ret.data(), len, format, args);
|
|
va_end(args);
|
|
|
|
ret.pop_back();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
std::string CvtRelativePath(std::string path_cur, std::string_view path)
|
|
{
|
|
if (!IsRelativePath(path))
|
|
return std::string{ path };
|
|
|
|
|
|
//直到首位不是 “./”和“../”
|
|
size_t i = 0;
|
|
size_t size = path.size();
|
|
while ((i < size)
|
|
&& (path[i] == '.'))
|
|
{
|
|
if ((i + 1 < size)
|
|
&& (path[i + 1] == '/'))
|
|
{//当前目录
|
|
i += 2;
|
|
}
|
|
else if ((i + 2 < size)
|
|
&& (path[i + 1] == '.' && path[i + 2] == '/'))
|
|
{//向上目录
|
|
i += 3;
|
|
path_cur.pop_back();
|
|
Erase::TailFromLast(path_cur, '/');
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
return path_cur + std::string(path.begin() + i, path.end());
|
|
}
|
|
|
|
bool GetPathAndRes(std::string_view path_root, std::string_view path_name, std::string& path_real, std::string& res_name, std::string_view name /*= ""*/)
|
|
{
|
|
if (IsRelativePath(path_name))
|
|
{
|
|
path_real = fmt::format("{}{}", path_root, path_name);
|
|
if (name.empty())
|
|
{
|
|
res_name = path_name;
|
|
if (Erase::TailFromLast(res_name, '.'))
|
|
res_name.pop_back();//去后缀
|
|
Every::Replace(res_name, '/', '.');//斜杠变.
|
|
}
|
|
else
|
|
res_name = name;
|
|
}
|
|
else
|
|
{
|
|
if (name.empty())
|
|
{
|
|
path_real = path_name;
|
|
res_name = "error";
|
|
log_err0("绝对路径加载,必须设定资源名字!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
path_real = path_name;
|
|
res_name = name;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::string GetResName(std::string_view path_root, std::string_view path_name)
|
|
{
|
|
std::string name = std::string{ path_name };
|
|
auto iter_path = name.find(path_root);
|
|
if (iter_path != 0)
|
|
{
|
|
log_err0("路径错误:" + std::string{ name });
|
|
}
|
|
else
|
|
name.erase(0, path_root.size());
|
|
|
|
if (Erase::TailFromLast(name, '.'))//去后缀
|
|
{
|
|
name.pop_back();
|
|
}
|
|
|
|
if (Any::Equal(name, '\\'))
|
|
{
|
|
log_err("路径存在反斜杠:{}", name);
|
|
Every::Replace(name, '\\', '.');
|
|
}
|
|
Every::Replace(name, '/', '.');
|
|
return name;
|
|
}
|
|
|
|
std::vector<std::string> FormatString2(const Vector2<std::string>& arr)
|
|
{
|
|
auto W = arr.GetWidth();
|
|
auto H = arr.GetHeight();
|
|
using Index = decltype(W);
|
|
|
|
//每一列得到一个最大宽度
|
|
std::vector<Index> mul_col;
|
|
mul_col.resize(W);
|
|
for (Index j = 0; j < H; ++j)
|
|
{
|
|
for (Index i = 0; i < W; ++i)
|
|
{
|
|
if (arr[j][i].size() > mul_col[i])
|
|
mul_col[i] = (Index)arr[j][i].size();
|
|
}
|
|
}
|
|
//合并每行
|
|
std::vector<std::string> ret;
|
|
ret.resize(H);
|
|
for (Index i = 0; i < W; ++i)
|
|
{
|
|
std::string fmt = std::string("{:<") + std::to_string(mul_col[i] + 1) + "}";
|
|
for (Index j = 0; j < H; ++j)
|
|
{
|
|
ret[j] += fmt::vformat(fmt, fmt::make_format_args(arr[j][i]));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::vector<std::string> ParseCommand(std::string_view cmd)
|
|
{
|
|
std::vector<std::string> ret;
|
|
if (cmd.empty())
|
|
return ret;
|
|
size_t i = 0;
|
|
// 跳过起始空白
|
|
while (cmd[i] == ' ' || cmd[i] == '\t')
|
|
{
|
|
++i;
|
|
}
|
|
|
|
int mode = 0; // 空白模式、普通匹配、字符串模式
|
|
std::string temp;
|
|
while (cmd[i])
|
|
{
|
|
const char& ch = cmd[i];
|
|
if (mode == 0)
|
|
{
|
|
if (ch == '\"')
|
|
mode = 2;
|
|
else if (ch == ' ' || ch == '\t')
|
|
;
|
|
else
|
|
{
|
|
temp.push_back(ch);
|
|
mode = 1;
|
|
}
|
|
}
|
|
else if (mode == 1)
|
|
{
|
|
if (ch == ' ' || ch == '\t')
|
|
{
|
|
ret.push_back(temp);
|
|
temp.clear();
|
|
mode = 0;
|
|
}
|
|
else
|
|
temp.push_back(ch);
|
|
}
|
|
else if (mode == 2)
|
|
{
|
|
if (ch == '\"' && (i + 1 >= cmd.size() || cmd[i + 1] == ' ' || cmd[i + 1] == '\t'))
|
|
{
|
|
ret.push_back(temp);
|
|
temp.clear();
|
|
mode = 0;
|
|
}
|
|
else
|
|
{
|
|
temp.push_back(ch);
|
|
}
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
// 添加最后一个参数
|
|
if (!temp.empty())
|
|
ret.push_back(temp);
|
|
return ret;
|
|
}
|
|
|
|
std::string FillEndl(std::string_view str, char ch /*= ' '*/)
|
|
{
|
|
std::wstring wstr = CodeCvt::Utf8ToWideChar(str);
|
|
|
|
size_t max_w = 0;
|
|
size_t count = 0;
|
|
for (auto& iter : wstr)
|
|
{
|
|
if (iter != L'\n')
|
|
count += Wcwidth(iter);
|
|
else
|
|
{
|
|
if (count > max_w)
|
|
max_w = count;
|
|
count = 0;
|
|
}
|
|
}
|
|
std::wstring ret;
|
|
count = 0;
|
|
for (auto& iter : wstr)
|
|
{
|
|
if (iter != L'\n')
|
|
{
|
|
ret.push_back(iter);
|
|
count += Wcwidth(iter);
|
|
}
|
|
else
|
|
{
|
|
for (; count < max_w; ++count)
|
|
ret.push_back(ch);
|
|
ret.push_back(L'\n');
|
|
count = 0;
|
|
}
|
|
}
|
|
return CodeCvt::WideCharToUtf8(ret);
|
|
}
|
|
|
|
size_t Wcwidth(wchar_t ch)
|
|
{
|
|
int ret = wcwidth(ch);
|
|
//log_warn("{}:{}", GetUtf8ByWchar(ch), ret);
|
|
if (ret < 0)
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
|
|
std::string to_string(BufferView buf)
|
|
{
|
|
std::string ret = { (char*)buf.data(), buf.size() };
|
|
return ret;
|
|
}
|
|
|
|
|
|
std::string to_string_hex(BufferView buf, bool upper/* = false*/, bool add_tag /*= false*/)
|
|
{
|
|
std::string ret;
|
|
if (add_tag)
|
|
ret += "0x";
|
|
|
|
if (!upper)
|
|
{
|
|
for (size_t i = 0; i < buf.size(); ++i)
|
|
{
|
|
ret += fmt::format("{:02x}", (unsigned char)buf[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < buf.size(); ++i)
|
|
{
|
|
ret += fmt::format("{:02X}", (unsigned char)buf[i]);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::string to_string_check(BufferView buf, bool tips)
|
|
{
|
|
std::string ret = { (char*)buf.data(), buf.size() };
|
|
if (!CodeCvt::Utf8::Check(ret))
|
|
{
|
|
if(tips)
|
|
log_warn("转换失败,非utf8编码!");
|
|
return {};
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::string to_string_auto(BufferView buf, bool add_tag /*= false*/)
|
|
{
|
|
std::string ret = to_string_check(buf, false);
|
|
if (!ret.empty())
|
|
return ret;
|
|
return to_string_hex(buf);
|
|
}
|
|
|
|
}
|
|
|
|
|