KisaragiLibrary
 
読み取り中…
検索中…
一致する文字列を見つけられません
Json.hpp
[詳解]
1#pragma once
2
3/**
4 * @file Json.hpp
5 * @brief Json形式のデータを取り扱うためのヘッダ
6 * @author 樺澤陽向
7 * @date 2025/05/08
8 * @since ver1.0.0 コメント追加
9 */
10
12#include <string>
13#include <vector>
14#include <variant>
15#include <unordered_map>
16#include <filesystem>
17#include <fstream>
18
19#include <memory>
20
21
22
23namespace Kisaragi_Lib
24{
25
26 namespace fs = std::filesystem;
27
28 //TODO これJsonの入れ子手動で出来なくない?
29
30 /// <summary>
31 /// Jsonデータを取り扱うクラス
32 /// </summary>
33 /// @since ver1.0.0 コメント追加
34 class Json
35 {
36 public:
37
38 Json() : value{nullptr}
39 {
40
41 }
42
43 Json(std::string _str) : value{ _str }
44 {
45
46 }
47
48 explicit Json(bool _bool) : value{ _bool }
49 {
50
51 }
52
53 explicit Json(float _float) : value{ _float }
54 {
55
56 }
57
58 explicit Json(int _int) : value{ _int }
59 {
60
61 }
62
63 // コピーコンストラクタとムーブコンストラクタ
64 Json(const Json& other) = default;
65 Json(Json&& other) noexcept = default;
66 Json& operator=(Json&& other) noexcept = default;
67
68 Json& operator=(const Json& other)
69 {
70 if (this != &other)
71 {
72 value = other.value;
73 }
74 return *this;
75 }
76
77 template<class T>
78 const T& Get() const
79 {
80 if (std::holds_alternative<T>(value))
81 {
82 return std::get<T>(value);
83 }
84
85 Debug::PrintAssertStatic("その型を保有していません");
86 }
87
88 template<class T>
89 T& Get()
90 {
91 if (std::holds_alternative<T>(value))
92 {
93 return std::get<T>(value);
94 }
95
96 Debug::PrintAssertStatic("その型を保有していません");
97 }
98
99 //TODO Debug
100 template<class T>
101 const bool IsType()
102 {
103 if (std::holds_alternative<T>(value))
104 {
105 return true;
106 }
107
108 return false;
109 }
110
111 template<class T>
112 Json& operator=(const T _in)
113 {
114 value = _in;
115
116 return *this;
117 }
118
119 // 数値型(int, short, longなど)に限定したコンストラクタ
120 template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
121 Json& operator[](const T _index)
122 {
123 int index{ _index };
124
125 if (!std::holds_alternative<std::vector<Json>>(value))
126 {
127 value = std::vector<Json>{};
128 }
129
130 // 配列が小さすぎる場合にresizeする
131 auto& vec = std::get<std::vector<Json>>(value);
132 if (index >= static_cast<int>(vec.size()))
133 {
134 vec.resize(index + 1);
135 }
136
137 return vec[index];
138 }
139
140 Json& operator[](const std::string& _key)
141 {
142 if (!std::holds_alternative<std::unordered_map<std::string, Json>>(value))
143 {
144 value = std::unordered_map<std::string, Json>{};
145 }
146
147 return std::get<std::unordered_map<std::string,Json>>(value)[_key];
148 }
149
150
151 /// <summary>
152 /// 自身をJsonファイルとして書き込みます
153 /// </summary>
154 /// <param name="_fileName">保存ファイル名(拡張子の省略可能)</param>
155 /// <param name="_directry">
156 /// 保存先ディレクトリのパス
157 /// デフォルト値は"./jsonFiles"
158 /// </param>
159 void Write(const fs::path& _fileName, const fs::path& _directry = "./jsonFiles")
160 {
161 if (value.index() < 5)
162 {
163 Debug::PrintAssertStatic("エラー : 最上位におけるのは配列か連想配列のみです");
164 return;
165 }
166
167 if (!fs::exists(_directry))
168 {
169 try
170 {
171 fs::create_directories(_directry);
172 }
173 catch (const fs::filesystem_error& e)
174 {
175 Debug::PrintAssertStatic("エラー : ファイルシステムでエラーが発生しました");
176 return;
177 }
178 }
179
180 // フォルダ位置
181 fs::path filePass = _directry;
182 // /= /を追加(ない場合のみ)
183 // ディレクトリ + ファイル名
184 filePass /= _fileName;
185 // 拡張子がない場合つける
186 filePass.replace_extension(".json");
187
188 std::ofstream file(filePass, std::ios::out | std::ios::trunc); // ファイルを開く(新規作成・上書き)
189
190 if (!file)
191 {
192 Debug::PrintAssertStatic("エラー: ファイルが開けませんでした");
193 return;
194 }
195
196 this->Write(file);
197
198 file.close();
199 return;
200 }
201
202
203
204 private:
205
206 void Write(std::ofstream& _file, unsigned int _depth = 0)
207 {
208 if (value.index() < TEXT_INDEX)
209 {
210 WriteNotText(_file,_depth);
211 }
212 else if (value.index() == TEXT_INDEX)
213 {
214 WriteText(_file, _depth);
215 }
216 else if(value.index() == TEXT_INDEX + 1)
217 {
218 WriteObject(_file, _depth);
219 }
220 else
221 {
222 WriteArray(_file, _depth);
223 }
224 }
225
226 void WriteNotText(std::ofstream& _file, unsigned int _depth = 0)
227 {
228 std::visit([&](auto&& arg)
229 {
230 using T = std::decay_t<decltype(arg)>;
231
232 if constexpr (std::is_same_v<T, std::nullptr_t>)
233 {
234 _file << "null";
235 }
236 else if constexpr (std::is_same_v<T, bool>)
237 {
238 _file << (arg ? "true" : "false");
239 }
240 else if constexpr (std::is_same_v<T, int> || std::is_same_v<T, float>)
241 {
242 _file << std::to_string(arg);
243 }
244
245 }, value);
246 }
247
248 void WriteText(std::ofstream& _file, unsigned int _depth = 0)
249 {
250 if (!_file) {
251 Debug::PrintAssertStatic("エラー: 有効なファイルではありません");
252 return;
253 }
254
255 _file << "\"" + std::get<std::string>(value) + "\"";
256
257 return;
258 }
259
260 void WriteObject(std::ofstream& _file, unsigned int _depth = 0)
261 {
262 if (!_file)
263 {
264 Debug::PrintAssertStatic("エラー: 有効なファイルではありません");
265 return;
266 }
267
268
269 _depth++;
270
271 _file << "{\n";
272
273 bool isFirst = true;
274
275
276 for (auto& element : std::get<std::unordered_map<std::string, Json>>(value))
277 {
278 if (isFirst)
279 {
280 isFirst = false;
281 }
282 else
283 {
284 _file << ",\n";
285 }
286
287 //改行を出力
288 WriteJsonDepth(_file, _depth);
289 //keyを出力
290 _file << "\"" + element.first + "\"" + " : ";
291 //値を出力
292 element.second.Write(_file, _depth);
293
294 }
295
296 _file << "\n";
297 //改行を出力
298 WriteJsonDepth(_file, _depth - 1);
299 _file << "}";
300 }
301
302 void WriteArray(std::ofstream& _file, unsigned int _depth = 0)
303 {
304 _depth++;
305
306 _file << "[\n";
307
308 bool isFirst = true;
309
310 for (auto& element : std::get<std::vector<Json>>(value))
311 {
312 if (isFirst)
313 {
314 isFirst = false;
315 }
316 else
317 {
318 _file << ",\n";
319 }
320
321 //改行を出力
322 WriteJsonDepth(_file, _depth);
323 //値を出力
324 element.Write(_file, _depth);
325
326 }
327
328 _file << "\n";
329 //改行を出力
330 WriteJsonDepth(_file, _depth - 1);
331 _file << "]";
332 }
333
334 void WriteJsonDepth(std::ofstream& _file, unsigned int _depth = 0)
335 {
336 if (!_file)
337 {
338 Debug::PrintAssertStatic("エラー: 有効なファイルではありません");
339 return;
340 }
341
342 _file << std::string(_depth, '\t');
343 }
344
345
346 /// <summary>
347 /// 値を管理する共用体
348 /// </summary>
349 using Value = std::variant
350 <
351 std::nullptr_t,
352 bool,
353 int,
354 float,
355 std::string,
356 std::unordered_map<std::string, Json>,
357 std::vector<Json>
358 >;
359
360 const int TEXT_INDEX = 4;
361
363 };
364
365
366 /// <summary>
367 /// Json読み込みクラス
368 /// </summary>
370 {
371 private:
372 std::string jsonFile;
373 size_t pos;
374
375 public:
376 /// <summary>
377 /// 自身が取り扱うJsonファイルを読み込みます
378 /// </summary>
379 /// <param name="_jsonFile">変換するJsonファイルのパス</param>
380 /// @since ver1.0.0 コメント追加
381 JsonParser(fs::path _jsonFile) : pos(0)
382 {
383 //拡張子がなければ付ける
384 _jsonFile.replace_extension(".json");
385
386 if (!fs::exists(_jsonFile))
387 {
388 Debug::PrintAssertStatic(" JsonContainer.Load() : ファイルが存在しません");
389 return;
390 }
391
392 std::ifstream file(_jsonFile); // ファイルを開く
393
394 if (!file) {
395 Debug::PrintAssertStatic("ファイルを開けませんでした。");
396 return;
397 }
398
399 jsonFile = std::string(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
400 file.close();
401
402 //制御文字を削除
404
405 }
406
407 /// <summary>
408 /// 読み込んだJsonファイルを変換し、Jsonクラスとして返します
409 /// </summary>
410 /// <returns>変換されたJsonクラス</returns>
412 {
413 SpaceSkip();
414 if (jsonFile[pos] == '{')
415 {
416 return ParseObject();
417 }
418 else if (jsonFile[pos] == '[')
419 {
420 return ParseArray();
421 }
422
423 return Json{};
424 }
425
426 private:
427
428 /// <summary>
429 /// ASCII code 32以下の制御文字を削除する
430 /// </summary>
431 /// <param name="str"></param>
432 void RemoveControlChars(std::string& str)
433 {
434 str.erase(std::remove_if(str.begin(), str.end(),
435 [](char c) { return (c < 32); }), str.end());
436 }
437
439 {
440 pos++; // '{' をスキップ
441 SpaceSkip();
442
443 Json json = Json();
444
445 while (jsonFile[pos] != '}')
446 {
447 std::string key;
448
449 key = ParseString();
450 SpaceSkip();
451
452 if (jsonFile[pos] != ':')
453 {
454 return json;
455 //throw std::runtime_error("Expected ':'");
456 }
457
458 pos++; //:をスキップ
459 SpaceSkip();
460
461 json[key] = ParseImpl();
462
463 SpaceSkip();
464
465 CommaSkip();
466
467 SpaceSkip();
468
469 }
470
471 if (jsonFile[pos] == '}')
472 {
473 pos++;
474 }
475
476 return json;
477 }
478
480 {
481 pos++; // '{' をスキップ
482
483 Json json = Json{};
484
485 int i = 0;
486 while (jsonFile[pos] != ']')
487 {
488 SpaceSkip();
489
490 json[i] = ParseImpl();
491
492 SpaceSkip();
493
494 CommaSkip();
495
496 SpaceSkip();
497
498 i++;
499 }
500
501 if (jsonFile[pos] == ']')
502 {
503 pos++;
504 }
505
506 return json;
507 }
508
509 std::string ParseString()
510 {
511 std::string result;
512 pos++; // '"' をスキップ
513
514 while (pos < jsonFile.size() && jsonFile[pos] != '"') {
515 result += jsonFile[pos++];
516 }
517
518 pos++; // '"' をスキップ
519 return result;
520 }
521
522 std::string ParseNotString()
523 {
524 std::string result;
525
526 while (pos < jsonFile.size() && jsonFile[pos] != ',' && jsonFile[pos] != ']' && jsonFile[pos] != '}') {
527 result += jsonFile[pos++];
528 }
529
530 return Trim(result);
531 }
532
533 bool isNumber(const std::string& str)
534 {
535 try {
536 std::stod(str); // ストリングを数値に変換できるか試す
537 return true;
538 }
539 catch (...) {
540 return false;
541 }
542 }
543
545 {
546 SpaceSkip();
547 if (jsonFile[pos] == '{')
548 {
549 return ParseObject();
550 }
551 else if (jsonFile[pos] == '[')
552 {
553 return ParseArray();
554 }
555 else if (jsonFile[pos] == '\"')
556 {
557 return Json(ParseString());
558 }
559 else if (jsonFile[pos] != ',')
560 {
561 std::string str = ParseNotString();
562
563 if (str == "true")
564 {
565 return Json(true);
566 }
567 else if (str == "false")
568 {
569 return Json(false);
570 }
571 else if (str.find(".") != std::string::npos || !str.empty() && str.back() == 'f')
572 {
573 if (!str.empty() && str.back() == 'f') {
574 str.pop_back(); // 末尾の 'f' を削除
575 }
576
577 return Json(std::stof(str));
578 }
579 else if (isNumber(str))
580 {
581 return Json(std::stoi(str));
582 }
583
584 return Json{};
585 }
586 else
587 {
588 //何も入力されていないためnull
589 return Json{};
590 }
591 }
592
593 std::string Trim(const std::string& str)
594 {
595 size_t first = str.find_first_not_of(" \t\n\r");
596 if (first == std::string::npos)
597 return "";
598
599 size_t last = str.find_last_not_of(" \t\n\r");
600 return str.substr(first, (last - first + 1));
601 }
602
604 {
605 while (pos < jsonFile.size() && std::isspace(jsonFile[pos]))
606 {
607 pos++;
608 }
609 }
610
612 {
613 if (pos < jsonFile.size() && jsonFile[pos] == ',')
614 {
615 pos++; //, をスキップ
616 }
617 }
618 };
619}
DebugConsole操作クラス
static void PrintAssertStatic(const std::string _in)
エラー出力用コンソール出力(文字色しか変わらない)
Definition Debug.cpp:152
Jsonデータを取り扱うクラス
Definition Json.hpp:35
std::variant< std::nullptr_t, bool, int, float, std::string, std::unordered_map< std::string, Json >, std::vector< Json > > Value
値を管理する共用体
Definition Json.hpp:349
Json & operator[](const std::string &_key)
Definition Json.hpp:140
Json & operator=(Json &&other) noexcept=default
Json & operator=(const Json &other)
Definition Json.hpp:68
void WriteArray(std::ofstream &_file, unsigned int _depth=0)
Definition Json.hpp:302
Json()
Definition Json.hpp:38
void WriteJsonDepth(std::ofstream &_file, unsigned int _depth=0)
Definition Json.hpp:334
const int TEXT_INDEX
Definition Json.hpp:360
const bool IsType()
Definition Json.hpp:101
Json(float _float)
Definition Json.hpp:53
Json(const Json &other)=default
void WriteObject(std::ofstream &_file, unsigned int _depth=0)
Definition Json.hpp:260
Json(int _int)
Definition Json.hpp:58
Json(bool _bool)
Definition Json.hpp:48
void Write(const fs::path &_fileName, const fs::path &_directry="./jsonFiles")
自身をJsonファイルとして書き込みます
Definition Json.hpp:159
T & Get()
Definition Json.hpp:89
const T & Get() const
Definition Json.hpp:78
Value value
Definition Json.hpp:362
void Write(std::ofstream &_file, unsigned int _depth=0)
Definition Json.hpp:206
Json(Json &&other) noexcept=default
Json & operator=(const T _in)
Definition Json.hpp:112
void WriteText(std::ofstream &_file, unsigned int _depth=0)
Definition Json.hpp:248
void WriteNotText(std::ofstream &_file, unsigned int _depth=0)
Definition Json.hpp:226
Json & operator[](const T _index)
Definition Json.hpp:121
Json(std::string _str)
Definition Json.hpp:43
Json ParseArray()
Definition Json.hpp:479
std::string jsonFile
Definition Json.hpp:372
Json Parse()
読み込んだJsonファイルを変換し、Jsonクラスとして返します
Definition Json.hpp:411
void CommaSkip()
Definition Json.hpp:611
std::string ParseString()
Definition Json.hpp:509
JsonParser(fs::path _jsonFile)
自身が取り扱うJsonファイルを読み込みます
Definition Json.hpp:381
bool isNumber(const std::string &str)
Definition Json.hpp:533
size_t pos
Definition Json.hpp:373
std::string Trim(const std::string &str)
Definition Json.hpp:593
std::string ParseNotString()
Definition Json.hpp:522
Json ParseImpl()
Definition Json.hpp:544
Json ParseObject()
Definition Json.hpp:438
void RemoveControlChars(std::string &str)
ASCII code 32以下の制御文字を削除する
Definition Json.hpp:432
void SpaceSkip()
Definition Json.hpp:603
Definition Accessor.hpp:110