improve JSON parser
This commit is contained in:
parent
95b145bece
commit
2c9ac1da3c
@ -197,7 +197,7 @@ public:
|
|||||||
void AddSentence(QString sentence)
|
void AddSentence(QString sentence)
|
||||||
{
|
{
|
||||||
if (sentence.size() > maxSentenceSize) sentence = SENTENCE_TOO_BIG;
|
if (sentence.size() > maxSentenceSize) sentence = SENTENCE_TOO_BIG;
|
||||||
if (!showOriginal && sentence.count(u8"\x200b \n")) sentence = sentence.split(u8"\x200b \n")[1];
|
if (!showOriginal && sentence.contains(u8"\x200b \n")) sentence = sentence.split(u8"\x200b \n")[1];
|
||||||
sanitize(sentence);
|
sanitize(sentence);
|
||||||
sentence.chop(std::distance(std::remove(sentence.begin(), sentence.end(), QChar::Tabulation), sentence.end()));
|
sentence.chop(std::distance(std::remove(sentence.begin(), sentence.end(), QChar::Tabulation), sentence.end()));
|
||||||
sentenceHistory.push_back(sentence);
|
sentenceHistory.push_back(sentence);
|
||||||
|
@ -61,4 +61,4 @@ std::string Escape(const std::string& text)
|
|||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TEST(assert(JSON::Parse(LR"([{"string":"hello world","boolean":false,"number": 1.67e+4,"null": null,"array":[]},"hello world"])")))
|
TEST(assert(JSON::Parse<wchar_t>(LR"([{"string":"hello world","boolean":false,"number":1.67e+4,"null":null,"array":[]},"hello world"])")))
|
||||||
|
@ -63,14 +63,52 @@ namespace JSON
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename C>
|
template <typename C>
|
||||||
std::pair<std::basic_string<C>, int> Unescape(std::basic_string_view<C> text)
|
struct Value : private std::variant<std::monostate, std::nullopt_t, bool, double, std::basic_string<C>, std::vector<Value<C>>, std::unordered_map<std::basic_string<C>, Value<C>>>
|
||||||
|
{
|
||||||
|
using std::variant<std::monostate, std::nullopt_t, bool, double, std::basic_string<C>, std::vector<Value<C>>, std::unordered_map<std::basic_string<C>, Value<C>>>::variant;
|
||||||
|
|
||||||
|
explicit operator bool() const { return index(); }
|
||||||
|
bool IsNull() const { return index() == 1; }
|
||||||
|
auto Boolean() const { return std::get_if<bool>(this); }
|
||||||
|
auto Number() const { return std::get_if<double>(this); }
|
||||||
|
auto String() const { return std::get_if<std::basic_string<C>>(this); }
|
||||||
|
auto Array() const { return std::get_if<std::vector<Value<C>>>(this); }
|
||||||
|
auto Object() const { return std::get_if<std::unordered_map<std::basic_string<C>, Value<C>>>(this); }
|
||||||
|
|
||||||
|
const Value<C>& operator[](std::basic_string<C> key) const
|
||||||
|
{
|
||||||
|
static const Value<C> failure;
|
||||||
|
if (auto object = Object()) if (auto it = object->find(key); it != object->end()) return it->second;
|
||||||
|
return failure;
|
||||||
|
}
|
||||||
|
const Value<C>& operator[](int i) const
|
||||||
|
{
|
||||||
|
static const Value<C> failure;
|
||||||
|
if (auto array = Array()) if (i < array->size()) return array->at(i);
|
||||||
|
return failure;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename C, int maxDepth = 25>
|
||||||
|
Value<C> Parse(const std::basic_string<C>& text, int64_t& i, int depth)
|
||||||
|
{
|
||||||
|
if (depth > maxDepth) return {};
|
||||||
|
C ch;
|
||||||
|
auto SkipWhitespace = [&]
|
||||||
|
{
|
||||||
|
while (i < text.size() && (text[i] == ' ' || text[i] == '\n' || text[i] == '\r' || text[i] == '\t')) ++i;
|
||||||
|
if (i >= text.size()) return true;
|
||||||
|
ch = text[i];
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
auto ExtractString = [&]
|
||||||
{
|
{
|
||||||
std::basic_string<C> unescaped;
|
std::basic_string<C> unescaped;
|
||||||
int i = 0;
|
i += 1;
|
||||||
for (; i < text.size(); ++i)
|
for (; i < text.size(); ++i)
|
||||||
{
|
{
|
||||||
auto ch = text[i];
|
auto ch = text[i];
|
||||||
if (ch == '"') return { unescaped, i + 1 };
|
if (ch == '"') return i += 1, unescaped;
|
||||||
if (ch == '\\')
|
if (ch == '\\')
|
||||||
{
|
{
|
||||||
ch = text[i + 1];
|
ch = text[i + 1];
|
||||||
@ -91,53 +129,7 @@ namespace JSON
|
|||||||
}
|
}
|
||||||
else unescaped.push_back(ch);
|
else unescaped.push_back(ch);
|
||||||
}
|
}
|
||||||
return { unescaped, i };
|
return unescaped;
|
||||||
}
|
|
||||||
|
|
||||||
template <typename C>
|
|
||||||
struct Value : private std::variant<std::monostate, std::nullopt_t, bool, double, std::basic_string<C>, std::vector<Value<C>>, std::unordered_map<std::basic_string<C>, Value<C>>>
|
|
||||||
{
|
|
||||||
using std::variant<std::monostate, std::nullopt_t, bool, double, std::basic_string<C>, std::vector<Value<C>>, std::unordered_map<std::basic_string<C>, Value<C>>>::variant;
|
|
||||||
|
|
||||||
explicit operator bool() const { return index(); }
|
|
||||||
bool IsNull() const { return index() == 1; }
|
|
||||||
auto Boolean() const { return std::get_if<bool>(this); }
|
|
||||||
auto String() const { return std::get_if<std::basic_string<C>>(this); }
|
|
||||||
auto Array() const { return std::get_if<std::vector<Value<C>>>(this); }
|
|
||||||
auto Object() const { return std::get_if<std::unordered_map<std::basic_string<C>, Value<C>>>(this); }
|
|
||||||
|
|
||||||
const Value<C>& operator[](std::basic_string<C> key) const
|
|
||||||
{
|
|
||||||
static const Value<C> failure;
|
|
||||||
if (auto object = Object()) if (auto it = object->find(key); it != object->end()) return it->second;
|
|
||||||
return failure;
|
|
||||||
}
|
|
||||||
const Value<C>& operator[](int i) const
|
|
||||||
{
|
|
||||||
static const Value<C> failure;
|
|
||||||
if (auto array = Array()) if (i < array->size()) return array->at(i);
|
|
||||||
return failure;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename C, int maxDepth = 25>
|
|
||||||
Value<C> Parse(std::basic_string_view<C> text, int64_t& i, int depth)
|
|
||||||
{
|
|
||||||
if (depth > maxDepth) return {};
|
|
||||||
C ch;
|
|
||||||
auto SkipWhitespace = [&]
|
|
||||||
{
|
|
||||||
while (i < text.size() && (text[i] == ' ' || text[i] == '\n' || text[i] == '\r' || text[i] == '\t')) ++i;
|
|
||||||
if (i >= text.size()) return true;
|
|
||||||
ch = text[i];
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
auto ExtractString = [&]
|
|
||||||
{
|
|
||||||
i += 1;
|
|
||||||
auto [string, length] = Unescape(text.substr(i));
|
|
||||||
i += length;
|
|
||||||
return string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (SkipWhitespace()) return {};
|
if (SkipWhitespace()) return {};
|
||||||
@ -155,9 +147,10 @@ namespace JSON
|
|||||||
|
|
||||||
if (ch == '-' || (ch >= '0' && ch <= '9'))
|
if (ch == '-' || (ch >= '0' && ch <= '9'))
|
||||||
{
|
{
|
||||||
// no numbers currently used, add an actual parser when needed
|
std::string number;
|
||||||
while (i < text.size() && ((text[i] >= '0' && text[i] <= '9') || text[i] == '-' || text[i] == '+' || text[i] == 'e' || text[i] == 'E' || text[i] == '.')) ++i;
|
for (; i < text.size() && ((text[i] >= '0' && text[i] <= '9') || text[i] == '-' || text[i] == '+' || text[i] == 'e' || text[i] == 'E' || text[i] == '.'); ++i)
|
||||||
return 0.0;
|
number.push_back(text[i]);
|
||||||
|
return strtod(number.c_str(), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '"') return ExtractString();
|
if (ch == '"') return ExtractString();
|
||||||
@ -203,6 +196,6 @@ namespace JSON
|
|||||||
Value<C> Parse(const std::basic_string<C>& text)
|
Value<C> Parse(const std::basic_string<C>& text)
|
||||||
{
|
{
|
||||||
int64_t start = 0;
|
int64_t start = 0;
|
||||||
return Parse((std::basic_string_view<C>)text, start, 0);
|
return Parse(text, start, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user