C中的JSON解析器(打印JSON)

时间:2012-05-08 21:03:06

标签: c json printf

首先让我说我不是C的专家。我一直在审查JSON解析器的代码。

我想了解这段代码。

/* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str)
{
    const char *ptr;
    char *ptr2,*out;
    int len=0;
    unsigned char token;

    if (!str)
        return cJSON_strdup("");
    ptr = str;
    while ((token = *ptr) && ++len) {
        if (strchr("\"\\\b\f\n\r\t", token))
            len++;
        else if (token < 32)
            len += 5;
        ptr++;
    }

    out = (char*)cJSON_malloc(len + 3);
    if (!out)
      return 0;

    ptr2 = out;
    ptr = str;
    *ptr2++ = '\"';
    while (*ptr) {
        if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
            *ptr2++ = *ptr++;
        else {
            *ptr2++ = '\\';
            switch (token = *ptr++) {
                case '\\':      *ptr2++='\\';   break;
                case '\"':      *ptr2++='\"';   break;
                case '\b':      *ptr2++='b';    break;
                case '\f':      *ptr2++='f';    break;
                case '\n':      *ptr2++='n';    break;
                case '\r':      *ptr2++='r';    break;
                case '\t':      *ptr2++='t';    break;
                default:
                    /* escape and print */
                    sprintf(ptr2, "u%04x", token);
                    ptr2 += 5;
                    break;
            }
        }
    }
    *ptr2++ = '\"';
    *ptr2++ = 0;
    return out;
}

这个代码实际工作原理的一般性总结真的很棒,我的印象是它正在“美化”JSON字符串,这是正确的吗?

乍一看似乎是用r取代\ r \ n,但这有什么意义呢?

我一直在研究sprintf的功能,但是对于简单的事情,例如打印货币值或其他格式问题。但是我还没有弄清楚sprintf函数在这里做了什么:

sprintf(ptr2,"u%04x",token);ptr2+=5;

ptr2 + = 5的目的是什么?

对此的任何见解都会有所帮助。

3 个答案:

答案 0 :(得分:1)

此代码正在执行的操作是将非打印字符(例如U + 000A(换行符)替换为字符串中的转义序列,例如\n(两个字符\\和{{1} })。

变量n指向输出中的当前点,变量ptr2指向正在写入输出的字符串中的当前点。

ptr

相比之下,

// Write "u" followed by a 4-digit hexadecimal number to the output
sprintf(ptr2,"u%04x",token);
// Advance the output pointer by five spaces
ptr2 += 5; 

相同
*ptr2++ = 'r';

答案 1 :(得分:1)

该函数正在转义字符串内容,而不是美化它 - 例如它将回车字符(ASCII代码13)转换为字符串\r,它会转换其代码中的其他不可打印字符。 / p>

sprintf(ptr2,"u%04x",token);

ptr2的十六进制表示放入tokenx),用0填充为长度为四个字符(04) ,并以u为前缀 - 以下

ptr2+=5;

ptr2指针移到刚刚由sprintf生成的字符串后面 - 这是5个字符长。

答案 2 :(得分:1)

它正在做的是将控制字符转换为通常在C源代码中使用的转义序列。

if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') 
    *ptr2++=*ptr++;

这基本上是说“如果我们有正常的字符,如字母,数字等,只需将其直接从输入复制到输出。”

 else
 {
     *ptr2++='\\';

否则,我们将在输出中生成一个转义序列,它将以反斜杠开头。

     switch (token=*ptr++)
     {
         case '\\':      *ptr2++='\\';   break;
         case '\"':      *ptr2++='\"';   break;
         case '\b':      *ptr2++='b';    break;

然后,根据它找到的控制字符,它会生成转义序列的第二个字符,因此输入中的实际“退格”字符(将比较等于'\ b')将生成两个字符`输出中的''和'b'。

          case '\f':      *ptr2++='f';    break;
          case '\n':      *ptr2++='n';    break;
          case '\r':      *ptr2++='r';    break;
          case '\t':      *ptr2++='t';    break;

和换页,换行,回车和标签相同。

          default: sprintf(ptr2,"u%04x",token);ptr2+=5;   break;  

否则,以十六进制呈现控制字符,因此它变为\1234