0

私は 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 に置き換えているように見えますが、これは何を意味するのでしょうか。

私は sprintf の機能を研究してきましたが、通貨値の出力やその他のフォーマットの問題などの単純なことについてです。しかし、ここで sprintf 関数が何をしているのかはわかりません。

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

ptr2+=5 の目的は何ですか?

これについての洞察は本当に役に立ちます。

4

3 に答える 3

1

このコードが実行しているのは、U + 000A(改行)などの印刷不可能な文字を、\n(2文字、\\および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++;
于 2012-05-08T21:11:48.900 に答える
1

この関数は、文字列の内容を美化するのではなくエスケープしています。たとえば、復帰文字 (ASCII コード 13) を文字列\rに変換したり、コード内の他の印刷不可能な文字を変換したりします。

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

(the )ptr2の 16 進表現に配置し、長さが 4 文字になるように s を埋め込んで (the )、接頭辞として- を付けます。tokenx004u

ptr2+=5;

ptr2によって生成されたばかりの文字列の直後にポインタを移動しますsprintf。つまり、長さは 5 文字です。

于 2012-05-08T21:14:51.163 に答える
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;

次に、検出した制御文字に応じて、エスケープ シーケンスの 2 番目の文字を生成するため、入力内の実際の「バックスペース」文字 (「\b」と比較される) は、「\」と「\」の 2 文字を生成します。出力の「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;  

それ以外の場合は、制御文字を 16 進数でレンダリングすると、 のようになります\1234

于 2012-05-08T21:16:59.803 に答える