Implemented a JSON file format checking function.

This commit is contained in:
LuChiChick 2026-04-17 16:28:44 +08:00
parent 057438652a
commit b11e74e815
2 changed files with 400 additions and 2 deletions

View File

@ -3,8 +3,6 @@
extern "C" extern "C"
{ {
#include "stdio.h"
#include "stdlib.h"
#include "stdint.h" #include "stdint.h"
} }
@ -16,6 +14,13 @@ class Json_Arry; // Json 数组 元素必须是值
class Json_Object; // Json 对象 对象内必须是键值对序列 class Json_Object; // Json 对象 对象内必须是键值对序列
class Json_Value; // Json 值可以是数组、对象、字符串、浮点数值和整数值、逻辑值、NULL class Json_Value; // Json 值可以是数组、对象、字符串、浮点数值和整数值、逻辑值、NULL
/**
* @brief Json文件
* @param path_to_file
* @return std::string
*/
std::string JsonFile_FormatCheck(const char *path_to_file);
// Json 数组 // Json 数组
class Json_Arry class Json_Arry
{ {

View File

@ -1,5 +1,398 @@
#include "Json_Utilities.hpp" #include "Json_Utilities.hpp"
extern "C"
{
#include "stdio.h"
#include "stdlib.h"
}
#include "functional"
/**
* @brief Json文件
* @param path_to_file
* @return std::string
*/
std::string JsonFile_FormatCheck(const char *path_to_file)
{
// 尝试打开文件
FILE *pFile = fopen(path_to_file, "rb");
if (pFile == nullptr)
return "file \"" + std::string(path_to_file) + "\" open failed.";
// 行列计数
size_t rol_count = 1;
size_t column_count = 0;
std::string err_str;
// 跳过空白部分 return -> skip count
auto Lambda_skip_blank = [&](void) -> size_t
{
size_t read_count = 0;
while (true)
{
switch (fgetc(pFile))
{
case EOF:
return read_count;
case ' ':
column_count++;
read_count++;
break;
case '\r':
if (fgetc(pFile) == '\n')
{
read_count += 2;
rol_count++;
column_count = 0;
}
else
{
fseek(pFile, -2, SEEK_CUR);
return read_count;
}
break;
case '\n':
read_count++;
rol_count++;
column_count = 0;
break;
default:
fseek(pFile, -1, SEEK_CUR);
return read_count;
}
}
};
// 函数封装
std::function<std::string(void)> Check_Object;
std::function<std::string(void)> Check_Value;
std::function<std::string(void)> Check_Arry;
std::function<std::string(void)> Check_Pair;
// 函数定义
Check_Object = [&](void) -> std::string
{
Lambda_skip_blank();
char ch_get = fgetc(pFile);
if (ch_get != '{')
{
if (ch_get == EOF)
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
else
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
}
column_count++;
while (true)
{
Lambda_skip_blank();
ch_get = fgetc(pFile);
column_count++;
switch (ch_get)
{
case '}':
return std::string();
case '\"':
fseek(pFile, -1, SEEK_CUR);
column_count--;
{
std::string err_str = Check_Pair();
if (!err_str.empty())
return err_str;
// 结束后读取段
size_t now_rol_count = rol_count;
size_t now_column_count = column_count;
Lambda_skip_blank();
char ch_get = fgetc(pFile);
if ((ch_get != '}') && (ch_get != ','))
{
if (ch_get == ']')
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing '}'.";
else if (ch_get == EOF)
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
else
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing comma.";
}
fseek(pFile, -1, SEEK_CUR);
}
break;
case ',':
{
size_t now_rol_count = rol_count;
size_t now_column_count = column_count;
Lambda_skip_blank();
if (fgetc(pFile) != '\"')
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Unexpected ','.";
fseek(pFile, -1, SEEK_CUR);
break;
}
case EOF:
return std::string(path_to_file) + ':' + std::to_string(rol_count - 1) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
default:
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
}
}
};
Check_Value = [&](void) -> std::string
{
Lambda_skip_blank();
size_t begin_rol = rol_count;
size_t begin_column = column_count;
bool is_string = false;
char ch_get = fgetc(pFile);
// 判定第一个字符
switch (ch_get)
{
case EOF:
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
case '\"':
is_string = true;
break;
case '{':
fseek(pFile, -1, SEEK_CUR);
return Check_Object();
case '[':
fseek(pFile, -1, SEEK_CUR);
return Check_Arry();
default:
break;
}
// 判定为字符串
if (is_string)
{
column_count++;
while (true)
{
ch_get = fgetc(pFile);
column_count++;
switch (ch_get)
{
case '\"':
return std::string();
case '\\': // 转义符
ch_get = fgetc(pFile);
if (ch_get != EOF)
{
column_count++;
continue;
}
case EOF:
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
case '\n':
return std::string(path_to_file) + ':' + std::to_string(begin_rol) + ':' + std::to_string(begin_column) + ": Unfinished string.";
default:
continue;
}
}
}
else
fseek(pFile, -1, SEEK_CUR);
// 识别有效数值
std::string segment_read;
while (true)
{
bool segment_finish = false;
ch_get = fgetc(pFile);
column_count++;
switch (ch_get)
{
case EOF:
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
case '\r':
case ',':
case '}':
case ']':
column_count--;
fseek(pFile, -1, SEEK_CUR);
case ' ':
case '\n':
segment_finish = true;
break;
default:
segment_read += ch_get;
}
if (segment_finish)
break;
}
if ((segment_read == "true") || (segment_read == "false") || (segment_read == "null"))
return std::string();
// 数值识别
{
char *end_ptr;
strtod(segment_read.c_str(), &end_ptr);
// 未被完全转化、出现先导0、先导+、尾缀小数点时非法
if ((size_t(end_ptr - segment_read.c_str()) < segment_read.size()) || ((segment_read.c_str()[0] == '0') && (segment_read.size() > 1)) || (segment_read.c_str()[0] == '+') || end_ptr[-1] == '.')
return std::string(path_to_file) + ':' + std::to_string(begin_rol) + ':' + std::to_string(begin_column) + ": Invalid value \"" + segment_read + "\".";
}
return std::string();
};
Check_Arry = [&](void) -> std::string
{
Lambda_skip_blank();
char ch_get = fgetc(pFile);
if (ch_get != '[')
{
if (ch_get == EOF)
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
else
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
}
column_count++;
while (true)
{
Lambda_skip_blank();
ch_get = fgetc(pFile);
column_count++;
switch (ch_get)
{
case ']':
return std::string();
case ',':
{
size_t now_rol_count = rol_count;
size_t now_column_count = column_count;
Lambda_skip_blank();
if (fgetc(pFile) == ']')
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Unexpected ','.";
fseek(pFile, -1, SEEK_CUR);
break;
}
case EOF:
return std::string(path_to_file) + ':' + std::to_string(rol_count - 1) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
default:
{
column_count--;
fseek(pFile, -1, SEEK_CUR);
std::string err_str = Check_Value();
if (!err_str.empty())
return err_str;
// 结束后读取段
size_t now_rol_count = rol_count;
size_t now_column_count = column_count;
Lambda_skip_blank();
char ch_get = fgetc(pFile);
if ((ch_get != ',') && (ch_get != ']'))
{
if (ch_get == '}')
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing ']'.";
else if (ch_get == EOF)
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
else
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing comma.";
}
fseek(pFile, -1, SEEK_CUR);
}
}
}
};
Check_Pair = [&](void) -> std::string
{
Lambda_skip_blank();
char ch_get = fgetc(pFile);
if (ch_get != '\"')
{
if (ch_get == EOF)
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
else
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
}
column_count++;
// 遍历下一个引号
bool key_end = false;
while (true)
{
ch_get = fgetc(pFile);
column_count++;
switch (ch_get)
{
case '\"':
key_end = true;
break;
case '\n':
rol_count++;
column_count = 0;
break;
case EOF:
return std::string(path_to_file) + ':' + std::to_string(rol_count - 1) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
}
if (key_end)
break;
}
// 寻找键值对标记
Lambda_skip_blank();
ch_get = fgetc(pFile);
if (ch_get != ':')
{
if (ch_get == EOF)
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
else
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'. ':' is needed.";
}
column_count++;
return Check_Value();
};
// 跳过空白检查第一个字符
Lambda_skip_blank();
switch (fgetc(pFile))
{
case '[':
fseek(pFile, -1, SEEK_CUR);
err_str = Check_Arry();
break;
case '{':
fseek(pFile, -1, SEEK_CUR);
err_str = Check_Object();
break;
case EOF:
err_str = std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
break;
default:
err_str = std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Syntax error. Must begin with '{' or '['.";
}
// 关闭文件
fclose(pFile);
return err_str;
}
// std::string 构造 // std::string 构造
Json_Value::Json_Value(std::string str) : private_type(TYPE_STR), p_mem(malloc(sizeof(str))) Json_Value::Json_Value(std::string str) : private_type(TYPE_STR), p_mem(malloc(sizeof(str)))
{ {