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.

149 lines
4.6 KiB
C++

#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;
}