轉自:
用戶體驗第一的現代C++ JSON庫
// 最簡單的方式創建一個json對象 json obj = { { "null", nullptr }, { "number", 1 }, { "float", 1.3 }, { "boolean", false }, { "string", "中文測試" }, { "array", { 1, 2, true, 1.4 } }, { "object", { "key", "value" } } };
有沒有覺得單看這段代碼都有種js內味了(誤)。但是沒錯,上面這段代碼是C++
!
如果這引起了你的些許興趣,那就說明這個輪子成功了。
故事在前
造輪子的初衷是在兩年前,我記得那天空中都是圓圓的輪狀雲,突然想給自己的游戲做一個json格式的配置文件。當我百度一下C++ json庫時,被一張圖震驚了

當然震驚我的不是這些庫的性能,而是竟然足足有28個比較火的庫在互相對比。。還有哪個語言可以做到讓這么多人樂此不疲的為了一個小功能寫那些重復的邏輯和代碼呢?
然后我選了幾個比較熱門的庫看看usage,看的越多,震驚越多。
每一個庫的接口設計都無法獲得我在審美上的認同,甚至有些demo代碼又長又臭,這時候真的是想感嘆一句:我愛Golang!(誤)
於是那天的雲彩顯得越發的圓潤。直到那天我才知道,原來C++的設計美學從底子里就是圓形的。
所以各位手下留情,這個庫的存在並不是提升了多少性能,或者支持了多少json標准,而僅僅是為了美才誕生的。
這個庫的slogan也很簡單:
願天堂沒有C++
好了,認真介紹一下這個庫:
JSONXX
一個為 C++ 量身打造的輕量級 JSON 通用工具,輕松完成 JSON 解析和序列化功能,並和 C++ 輸入輸出流交互。
Nomango/jsonxx使用介紹
- 引入 jsonxx 頭文件
#include "jsonxx/json.hpp" using namespace jsonxx;
- 使用 C++ 的方式的創建 JSON 對象
使用 operator[]
為 JSON 對象賦值
json j; j["number"] = 1; j["float"] = 1.5; j["string"] = "this is a string"; j["boolean"] = true; j["user"]["id"] = 10; j["user"]["name"] = "Nomango";
使用 std::initializer_list
為 JSON 對象賦值
// 使用初始化列表構造數組 json arr = { 1, 2, 3 }; // 使用初始化列表構造對象 json obj = { { "user", { { "id", 10 }, { "name", "Nomango" } } } }; // 第二個對象 json obj2 = { { "nul", nullptr }, { "number", 1 }, { "float", 1.3 }, { "boolean", false }, { "string", "中文測試" }, { "array", { 1, 2, true, 1.4 } }, { "object", { "key", "value" } } };
使用輔助方法構造數組或對象
json arr = json::array({ 1 }); json obj = json::object({ "user", { { "id", 1 }, { "name", "Nomango" } } });
- 判斷 JSON 對象的值類型
// 判斷 JSON 值類型 bool is_null(); bool is_boolean(); bool is_integer(); bool is_float(); bool is_array(); bool is_object();
- 將 JSON 對象進行顯式或隱式轉換
// 顯示轉換 auto b = j["boolean"].as_boolean(); // bool auto i = j["number"].as_integer(); // int32_t auto f = j["float"].as_float(); // float const auto& arr = j["array"].as_array(); // arr 實際是 std::vector<json> 類型 const auto& obj = j["user"].as_object(); // obj 實際是 std::map<std::string, json> 類型 // 隱式轉換 bool b = j["boolean"]; int i = j["number"]; // int32_t 自動轉換為 int double d = j["float"]; // float 自動轉換成 double std::vector<json> arr = j["array"]; std::map<std::string, json> obj = j["user"];
若 JSON 值類型與待轉換類型不相同也不協變,會引發 json_type_error 異常
- 取值的同時判斷類型
int n; bool ret = j["boolean"].get_value(&n); // 若取值成功,ret 為 true
- JSON 對象類型和數組類型的遍歷
// 增強 for 循環 for (auto& j : obj) { std::cout << j << std::endl; } // 使用迭代器遍歷 for (auto iter = obj.begin(); iter != obj.end(); iter++) { std::cout << iter.key() << ":" << iter.value() << std::endl; }
- JSON 解析
// 解析字符串 json j = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); // 從文件讀取 JSON std::ifstream ifs("sample.json"); json j; ifs >> j; // 從標准輸入流讀取 JSON json j; std::cin >> j;
- JSON 序列化
// 序列化為字符串 std::string json_str = j.dump(); // 美化輸出,使用 4 個空格對輸出進行格式化 std::string pretty_str = j.dump(4, ' '); // 將 JSON 內容輸出到文件 std::ofstream ofs("output.json"); ofs << j << std::endl; // 將 JSON 內容輸出到文件,並美化 std::ofstream ofs("pretty.json"); ofs << std::setw(4) << j << std::endl; // 將 JSON 內容輸出到標准輸出流 json j; std::cout << j; // 可以使用 std::setw(4) 對輸出內容美化
更多
若你需要將 JSON 解析和序列化應用到非 std::basic_stream 流中,可以通過創建自定義 output_adapter
和 input_adapter
的方式實現。
實際上 json::parse() 和 json::dump() 函數也是通過自定義的 string_output_adapter
和 string_input_adapter
實現對字符串內容的輸入和輸出。
詳細內容請參考 json_parser.hpp 和 json_serializer.hpp。
寫在最后
很多朋友提到這個庫的風格和 nlohmann/json 很像,確實是的,當初看到這個庫的時候我感嘆一句“果然你能想到的別人都實現過了”,然后順手“借鑒”了一些功能補充進來(誤)
所以我也很推薦這個庫,nlohmann也許是JSON for modern C++ 的最佳實踐了吧!
對於中文,直接在vs2019下 gbk編碼文件,賦值中文后
j["happy"] = "中文";
然后取出 j["happy"].as_string().c_str(), 發現字符是按照gbk編碼存放:D6D0 CEC4.
而windows中,存放中文:
LPCWSTR cn = L"中文"; //看到它是放的unicode編碼。
調用windows的 ::MessageBox(NULL, (LPCWSTR)( j["happy"].as_string().c_str()), cn, MB_OK); 會顯示亂碼。
利用下面的轉換一下就好了,就會將gbk轉成unicode的 2d 4e 87 65
CString str = CString(c_char);
USES_CONVERSION;
LPCWSTR wszClassName = A2CW(W2A(str));
用這個網站觀察編碼,很不錯:http://www.mytju.com/classcode/tools/encode_gb2312.asp
如果本身字符是Unicode,存儲時轉成多字節,變成了gbk。讀取時再由c的char單字節str轉回多字節:
json obj;
obj[key]= wstring2string(title);
作為了string存儲。因為jsonxx不支持wstring。
讀取時 string2wstring(obj[key]) 返回了wstring;.c_str() 返回了wchar_t*.
#include <Windows.h> //將string轉換成wstring wstring string2wstring(string str) { wstring result; //獲取緩沖區大小,並申請空間,緩沖區大小按字符計算 int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0); TCHAR* buffer = new TCHAR[len + 1]; //多字節編碼轉換成寬字節編碼 MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len); buffer[len] = '\0'; //添加字符串結尾 //刪除緩沖區並返回值 result.append(buffer); delete[] buffer; return result; } //將wstring轉換成string string wstring2string(wstring wstr) { string result; //獲取緩沖區大小,並申請空間,緩沖區大小事按字節計算的 int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL); char* buffer = new char[len + 1]; //寬字節編碼轉換成多字節編碼 WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL); buffer[len] = '\0'; //刪除緩沖區並返回值 result.append(buffer); delete[] buffer; return result; }
前言
大家在學習或者使用Windows編程中,經常會碰到字符串之間的轉換,char*轉LPCWSTR也是其中一個比較常見的轉換。下面就列出幾種比較常用的轉換方法。大家可以根據自己的需求選擇相對應的方法,下面來一起學習學習吧。
1、通過MultiByteToWideChar函數轉換
MultiByteToWideChar函數是將多字節轉換為寬字節的一個API函數,它的原型如下:
1
2
3
4
5
6
7
8
|
int
MultiByteToWideChar(
UINT
CodePage,
// code page
DWORD
dwFlags,
// character-type options
LPCSTR
lpMultiByteStr,
// string to map
int
cbMultiByte,
// number of bytes in string
LPWSTR
lpWideCharStr,
// wide-character buffer
int
cchWideChar
// size of buffer
);
|
LPCWSTR實際上也是CONST WCHAR *類型
1
2
3
4
5
|
char
* szStr =
"測試字符串"
;
WCHAR
wszClassName[256];
memset
(wszClassName,0,
sizeof
(wszClassName));
MultiByteToWideChar(CP_ACP,0,szStr,
strlen
(szStr)+1,wszClassName,
sizeof
(wszClassName)/
sizeof
(wszClassName[0]));
|
2、通過T2W轉換宏
1
2
3
4
5
6
|
char
* szStr =
"測試字符串"
;
CString str = CString(szStr);
USES_CONVERSION;
LPCWSTR
wszClassName =
new
WCHAR
[str.GetLength()+1];
wcscpy((
LPTSTR
)wszClassName,T2W((
LPTSTR
)str.GetBuffer(NULL)));
str.ReleaseBuffer();
|
3、通過A2CW轉換
1
2
3
4
5
|
char
* szStr =
"測試字符串"
;
CString str = CString(szStr);
USES_CONVERSION;
LPCWSTR
wszClassName = A2CW(W2A(str));
str.ReleaseBuffer();
|
上述方法都是UniCode環境下測試的。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
網上看到的,好像最新是不是已經解決了。沒碰到這問題。