c++ - parsejson - string to object javascript
¿Escape de cadena JSON simple para C++? (3)
He escrito un simple escape JSON y funciones no escapadas. El código es público disponible en GitHub . Para cualquier persona interesada aquí está el código:
enum State {ESCAPED, UNESCAPED};
std::string escapeJSON(const std::string& input)
{
std::string output;
output.reserve(input.length());
for (std::string::size_type i = 0; i < input.length(); ++i)
{
switch (input[i]) {
case ''"'':
output += "///"";
break;
case ''/'':
output += "///";
break;
case ''/b'':
output += "//b";
break;
case ''/f'':
output += "//f";
break;
case ''/n'':
output += "//n";
break;
case ''/r'':
output += "//r";
break;
case ''/t'':
output += "//t";
break;
case ''//':
output += "////";
break;
default:
output += input[i];
break;
}
}
return output;
}
std::string unescapeJSON(const std::string& input)
{
State s = UNESCAPED;
std::string output;
output.reserve(input.length());
for (std::string::size_type i = 0; i < input.length(); ++i)
{
switch(s)
{
case ESCAPED:
{
switch(input[i])
{
case ''"'':
output += ''/"'';
break;
case ''/'':
output += ''/'';
break;
case ''b'':
output += ''/b'';
break;
case ''f'':
output += ''/f'';
break;
case ''n'':
output += ''/n'';
break;
case ''r'':
output += ''/r'';
break;
case ''t'':
output += ''/t'';
break;
case ''//':
output += ''//';
break;
default:
output += input[i];
break;
}
s = UNESCAPED;
break;
}
case UNESCAPED:
{
switch(input[i])
{
case ''//':
s = ESCAPED;
break;
default:
output += input[i];
break;
}
}
}
}
return output;
}
Tengo un programa muy simple que genera una cadena JSON simple que concatené de forma manual y salida a través de la secuencia std :: cout (la salida es realmente simple) pero tengo cadenas que pueden contener comillas dobles, llaves y Otros caracteres que podrían romper la cadena JSON. Así que necesito una biblioteca (o una función más precisa) para escapar de las cadenas de acuerdo con el estándar JSON, lo más ligero posible, nada más, nada menos.
Encontré algunas bibliotecas que se utilizan para codificar objetos enteros en JSON, pero teniendo en cuenta que mi programa es un archivo cpp de 900 líneas, prefiero no confiar en una biblioteca que es varias veces más grande que mi programa solo para lograr algo tan simple como esta.
Actualización : ¡No uses esto! vog ofrece una solución mucho más completa (e igualmente compacta) más abajo: https://.com/a/33799784
Este es un comienzo muy simple, aunque no maneja caracteres unicode no válidos. Si no espera ninguno de ellos en su salida, siéntase libre de usar esto ...
#include <string>
#include <sstream>
std::string escapeJsonString(const std::string& input) {
std::ostringstream ss;
for (auto iter = input.cbegin(); iter != input.cend(); iter++) {
//C++98/03:
//for (std::string::const_iterator iter = input.begin(); iter != input.end(); iter++) {
switch (*iter) {
case ''//': ss << "////"; break;
case ''"'': ss << "///""; break;
case ''/'': ss << "///"; break;
case ''/b'': ss << "//b"; break;
case ''/f'': ss << "//f"; break;
case ''/n'': ss << "//n"; break;
case ''/r'': ss << "//r"; break;
case ''/t'': ss << "//t"; break;
default: ss << *iter; break;
}
}
return ss.str();
}
Advertencia
Sea cual sea la solución que tome, tenga en cuenta que el estándar JSON requiere que escape todos los caracteres de control . Esto parece ser un error común. Muchos desarrolladores se equivocan.
Todos los caracteres de control significan todo desde ''/x00''
hasta ''/x1f''
, no solo aquellos con una representación corta como ''/x0a''
(también conocida como ''/n''
). Por ejemplo, debe escapar el carácter ''/x02''
como /u0002
.
Vea también: ECMA-404 El formato de intercambio de datos JSON , página 10
Solución simple
Si está seguro de que su cadena de entrada está codificada en UTF-8, puede mantener las cosas simples.
Como JSON le permite escapar de todo a través de /uXXXX
, incluso "
y /
, una solución simple es:
#include <sstream>
#include <iomanip>
std::string escape_json(const std::string &s) {
std::ostringstream o;
for (auto c = s.cbegin(); c != s.cend(); c++) {
if (*c == ''"'' || *c == ''//' || (''/x00'' <= *c && *c <= ''/x1f'')) {
o << "//u"
<< std::hex << std::setw(4) << std::setfill(''0'') << (int)*c;
} else {
o << *c;
}
}
return o.str();
}
Representación más corta
Para la representación más corta, puede usar accesos directos JSON, como /"
lugar de /u0022
. La siguiente función produce la representación JSON más corta de una cadena codificada en UTF-8:
#include <sstream>
#include <iomanip>
std::string escape_json(const std::string &s) {
std::ostringstream o;
for (auto c = s.cbegin(); c != s.cend(); c++) {
switch (*c) {
case ''"'': o << "///""; break;
case ''//': o << "////"; break;
case ''/b'': o << "//b"; break;
case ''/f'': o << "//f"; break;
case ''/n'': o << "//n"; break;
case ''/r'': o << "//r"; break;
case ''/t'': o << "//t"; break;
default:
if (''/x00'' <= *c && *c <= ''/x1f'') {
o << "//u"
<< std::hex << std::setw(4) << std::setfill(''0'') << (int)*c;
} else {
o << *c;
}
}
}
return o.str();
}
Declaración de cambio puro
También es posible llevarse bien con una instrucción de cambio puro, es decir, sin if
y <iomanip>
. Si bien esto es bastante engorroso, puede ser preferible desde el punto de vista de "seguridad por simplicidad y pureza":
#include <sstream>
std::string escape_json(const std::string &s) {
std::ostringstream o;
for (auto c = s.cbegin(); c != s.cend(); c++) {
switch (*c) {
case ''/x00'': o << "//u0000"; break;
case ''/x01'': o << "//u0001"; break;
...
case ''/x0a'': o << "//n"; break;
...
case ''/x1f'': o << "//u001f"; break;
case ''/x22'': o << "///""; break;
case ''/x5c'': o << "////"; break;
default: o << *c;
}
}
return o.str();
}
Usando una biblioteca
Es posible que desee echar un vistazo a https://github.com/nlohmann/json , que es una biblioteca eficiente de C ++ solo para encabezado (licencia MIT) que parece estar muy bien probada.
Puede llamar directamente a su método escape_string()
, o puede tomar su implementación de escape_string()
como punto de partida para su propia implementación: