You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
8.8 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "json_utils.h"
#include <cctype>
std::string json_trim(const std::string& s)
{
size_t b = s.find_first_not_of(" \t\r\n");
if (b == std::string::npos) return "";
size_t e = s.find_last_not_of(" \t\r\n");
return s.substr(b, e - b + 1);
}
static bool is_ws(char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; }
std::string json_get_raw(const std::string& text, const std::string& key)
{
std::string k = "\"" + key + "\"";
size_t pos = 0;
while ((pos = text.find(k, pos)) != std::string::npos)
{
bool key_ok = true;
if (pos > 0)
{
char c = text[pos - 1];
if (isalnum((unsigned char)c) || c == '_') key_ok = false;
}
if (key_ok)
{
size_t p = pos + k.size();
while (p < text.size() && is_ws(text[p])) ++p; // 跳过空白
if (p >= text.size()) return "";
if (text[p] != ':') { pos = pos + 1; continue; }
++p;
while (p < text.size() && is_ws(text[p])) ++p; // 跳过冒号后空白
if (p >= text.size()) return "";
char c = text[p];
if (c == '"')
{
// 字符串:读到配对引号
size_t q = p + 1;
while (q < text.size() && text[q] != '"') ++q;
return text.substr(p, q - p + 1);
}
else if (c == '{' || c == '[')
{
char close = (c == '{') ? '}' : ']';
int depth = 0;
size_t q = p;
for (; q < text.size(); ++q)
{
if (text[q] == '"')
{
++q;
while (q < text.size() && text[q] != '"') ++q;
}
else if (text[q] == c) ++depth;
else if (text[q] == close)
{
--depth;
if (depth == 0) { ++q; break; }
}
}
return text.substr(p, q - p);
}
else
{
// 数字 / true / false / null
size_t q = p;
while (q < text.size() && text[q] != ',' && text[q] != '}' && text[q] != ']' && !is_ws(text[q]))
++q;
return text.substr(p, q - p);
}
}
pos = pos + 1;
}
return "";
}
static std::string unquote(const std::string& raw)
{
std::string t = json_trim(raw);
if (t.size() >= 2 && t[0] == '"' && t[t.size() - 1] == '"')
return t.substr(1, t.size() - 2);
return t;
}
bool json_get_string(const std::string& text, const std::string& key, std::string& out)
{
std::string raw = json_get_raw(text, key);
if (raw.empty()) return false;
out = unquote(raw);
return true;
}
bool json_get_number(const std::string& text, const std::string& key, double& out)
{
std::string raw = json_get_raw(text, key);
if (raw.empty()) return false;
std::string t = json_trim(raw);
if (t.empty()) return false;
try { out = std::stod(t); return true; }
catch (...) { return false; }
}
bool json_get_bool(const std::string& text, const std::string& key, bool& out)
{
std::string raw = json_get_raw(text, key);
if (raw.empty()) return false;
std::string t = json_trim(raw);
if (t == "true") { out = true; return true; }
if (t == "false") { out = false; return true; }
double d;
if (json_get_number(text, key, d)) { out = (d != 0); return true; }
return false;
}
int json_get_point_array(const std::string& text, const std::string& key,
std::vector<std::pair<double, double>>& out)
{
std::string raw = json_get_raw(text, key);
if (raw.empty()) return 0;
std::string t = json_trim(raw);
if (t.empty() || t[0] != '[') return 0;
// 逐个匹配 "[数,数]" 子元素
size_t i = 1;
int cnt = 0;
while (i < t.size())
{
size_t l = t.find('[', i);
if (l == std::string::npos) break;
size_t r = t.find(']', l);
if (r == std::string::npos) break;
std::string ele = t.substr(l + 1, r - l - 1);
size_t comma = ele.find(',');
if (comma != std::string::npos)
{
try
{
double a = std::stod(json_trim(ele.substr(0, comma)));
double b = std::stod(json_trim(ele.substr(comma + 1)));
out.push_back(std::make_pair(a, b));
++cnt;
}
catch (...) {}
}
i = r + 1;
}
return cnt;
}
// ---- 枚举对象一级键名 ----
// 逐字符扫描,跟踪字符串与嵌套深度,只收集 depth==1 的键名。
std::vector<std::string> json_object_keys(const std::string& text, const std::string& group)
{
std::string obj = group.empty() ? text : json_get_raw(text, group);
std::vector<std::string> keys;
size_t p = obj.find('{');
if (p == std::string::npos) return keys;
int depth = 0;
bool in_str = false;
bool esc = false;
for (size_t i = p; i < obj.size(); ++i)
{
char c = obj[i];
if (in_str)
{
if (esc) { esc = false; continue; }
if (c == '\\') { esc = true; continue; }
if (c == '"') in_str = false;
continue;
}
if (c == '"')
{
// 字符串开始:若当前在对象层(depth>=1)且前一个非空白字符不是 ':' 或 ',',
// 则它是键名;否则是值(值已在 json_get_raw 中处理,这里跳过)。
size_t j = i + 1;
size_t q = obj.find('"', j);
while (q != std::string::npos && obj[q - 1] == '\\') q = obj.find('"', q + 1);
if (q == std::string::npos) break;
std::string tok = obj.substr(j, q - j);
size_t k = i;
while (k > p && is_ws(obj[k - 1])) --k;
char prev = (k > p) ? obj[k - 1] : '{';
if (depth == 1 && (prev == '{' || prev == ',')) keys.push_back(tok);
i = q; // 已整体消费该字符串(键或值),继续下一个字符
continue;
}
if (c == '{' || c == '[') { ++depth; continue; }
if (c == '}' || c == ']')
{
--depth;
if (depth <= 0) break;
continue;
}
}
return keys;
}
std::vector<std::string> json_object_keys(const std::string& text)
{
return json_object_keys(text, "");
}
// ---- 分组两级查找实现 ----
std::string json_get_raw(const std::string& text, const std::string& group, const std::string& key)
{
std::string obj = group.empty() ? text : json_get_raw(text, group);
if (obj.empty()) return "";
return json_get_raw(obj, key);
}
bool json_get_string(const std::string& text, const std::string& group, const std::string& key, std::string& out)
{
std::string raw = json_get_raw(text, group, key);
if (raw.empty()) return false;
out = unquote(raw);
return true;
}
bool json_get_number(const std::string& text, const std::string& group, const std::string& key, double& out)
{
std::string raw = json_get_raw(text, group, key);
if (raw.empty()) return false;
std::string t = json_trim(raw);
if (t.empty()) return false;
try { out = std::stod(t); return true; }
catch (...) { return false; }
}
bool json_get_bool(const std::string& text, const std::string& group, const std::string& key, bool& out)
{
std::string raw = json_get_raw(text, group, key);
if (raw.empty()) return false;
std::string t = json_trim(raw);
if (t == "true") { out = true; return true; }
if (t == "false") { out = false; return true; }
double d;
if (json_get_number(text, group, key, d)) { out = (d != 0); return true; }
return false;
}
int json_get_point_array(const std::string& text, const std::string& group, const std::string& key,
std::vector<std::pair<double, double>>& out)
{
std::string raw = json_get_raw(text, group, key);
if (raw.empty()) return 0;
std::string t = json_trim(raw);
if (t.empty() || t[0] != '[') return 0;
// 逐个匹配 "[数,数]" 子元素
size_t i = 1;
int cnt = 0;
while (i < t.size())
{
size_t l = t.find('[', i);
if (l == std::string::npos) break;
size_t r = t.find(']', l);
if (r == std::string::npos) break;
std::string ele = t.substr(l + 1, r - l - 1);
size_t comma = ele.find(',');
if (comma != std::string::npos)
{
try
{
double a = std::stod(json_trim(ele.substr(0, comma)));
double b = std::stod(json_trim(ele.substr(comma + 1)));
out.push_back(std::make_pair(a, b));
++cnt;
}
catch (...) {}
}
i = r + 1;
}
return cnt;
}