2012-05-08 155 views
0

讓我首先說我不是C中的專家。我一直在審查JSON解析器的代碼。C中的JSON解析器(打印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; 
} 

A的這段代碼是如何工作將是真正偉大真是總體概述,我的印象是,它是「美化」 JSON字符串,是正確的?

乍一看它似乎是用r替換\ r,但是這是什麼意思?

我一直在研究sprintf的功能,但對於簡單的事情,如打印出貨幣值或其他格式問題。但我還沒有弄清sprintf函數在這裏做什麼:

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

ptr2 + = 5的目的是什麼?

任何洞察到這真的會有所幫助。

回答

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

+0

很好解釋,TY爲它花時間! –

1

這段代碼正在做的是替換不可打印的字符,如U + 000A(換行)與所述串中的轉義序列如\n(兩個字符,\\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'; 

是一樣的,

// Write "r" to the output 
*ptr = 'r'; 
// Advance the output pointer one space 
ptr++; 
+0

豔太感謝你了 –

1

功能是逃避字符串內容,不美化它 - 例如把它轉換一個回車符( ASCII代碼13)轉換爲字符串\r,它轉換其代碼等中的其他非可打印字符。

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

地方到ptr2token(該x)的十六進制表示,填充與0 s至在lenght(該04)四個字符,並用u前綴 - 以下

ptr2+=5; 

移動ptr2指針緊跟在剛剛由sprintf生成的字符串之後 - 即5個字符長。