2014-03-03 51 views
2

有沒有簡單的方法來轉義printf()函數中的所有特殊字符?轉義printf中的所有特殊字符()

之所以我想知道如何做到這一點是因爲我打印的字符數可能包含特殊字符,如空字符(\0)和嗶聲字符,我只是想看到內容的字符串。

目前我使用下面的代碼

它爲空字符。什麼是逃避所有特殊字符最簡單的方法?

所有的
int length; 
char* data = GetData(length); // Fills the length as reference 

for(int i = 0; i < length; i++) 
{ 
    char c = data[ i ]; 
    printf("%c", (c == 0 ? '\\0' : data[ i ])); 
} 
+0

是否直接打印字符不只是工作?你只需要轉義char字面...我不明白爲什麼你需要使用。 – Dennis

+0

當前''\\ 0''是兩個字符:char''\\''和char''0''。這實際上是否將'\ 0'打印到'c == 0'的終端上? – turbulencetoo

+0

'\\ 0'是一個值爲23600(0x5C30)或12380(0x305C)的整數,不管字節順序如何。因此,%c將會打印\或0.機器的字節順序與編譯器的選擇無關。 –

回答

3

首先,'\\0'是兩個字符的文本,這確實應該是兩個字符的字符串。至於打印所有特殊字符轉義代碼,你需要一些更多的代碼:

switch (data[i]) 
{ 
case '\0': 
    printf("\\0"); 
    break; 
case '\n': 
    printf("\\n"); 
    break; 

/* Etc. */ 

default: 
    /* Now comes the "hard" part, because not all characters here 
    * are actually printable 
    */ 
    if (isprint(data[i])) 
     printf("%c", data[i]); /* Printable character, print it as usual */ 
    else 
     printf("\\x%02x", data[i]); /* Non-printable character, print as hex value */ 

    break; 
} 
+1

isprint函數將一個無符號字符作爲參數。它使用簽名字符崩潰。 此外,是否有更簡短的方式來打印不可打印的字符?十六進制值非常長。 –

+1

@MichielPater普通字符*全部*的值低於256,至少在所有帶有8位'char'類型的系統中。你的意思是你在擴展的ASCII範圍內有字符(即127以上)?另見例如[此引用](http://en.cppreference.com/w/c/string/byte/isprint),其中它指出「如果ch的值不能表示爲無符號字符並且不等於EOF「。 –

+0

@MichielPater如果十六進制數字很長,你確定'data'是一個數組(或指向)'char'嗎?你沒有使用'wchar_t'?你能舉一個輸出的例子嗎? –

1

使用isprint庫函數來確定字符是可打印:

#include <ctype.h> 
... 
if (isprint(data[i])) 
    printf(" %c", data[i]); // prints character 
else 
    printf(" %d", data[i]); // prints code value for character 
+1

isprint函數將一個無符號字符作爲參數。它使用簽名字符崩潰。 –

+0

@MichielPater:不符合[語言標準](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf),7.4.1.8;原型是'int isprint(int c);'如果它在一個普通的舊簽名'char'上崩潰,那麼在實現中或者它被調用的方式都有問題。 –

+0

不,signed char的符號擴展。這意味着在128到255之間的代碼點會給出'未定義的行爲'。編譯器可以自由地將'char'視爲'signed'或'unsigned'。 –

0

如果代碼需要與寫沒有歧義,用C語法:

#include <ctype.h> 
#include <string.h> 
#include <stdio.h> 

void EscapePrint(int ch) { 
    // Delete or adjust these 2 arrays per code's goals 
    // All simple-escape-sequence C11 6.4.4.4 
    static const char *escapev = "\a\b\t\n\v\f\r\"\'\?\\"; 
    static const char *escapec = "abtnvfr\"\'\?\\"; 
    char *p = strchr(escapev, ch); 
    if (p && *p) { 
    printf("\\%c", escapec[p - escapev]); 
    } else if (isprint(ch)) { 
    fputc(ch, stdout); 
    } else { 
    // Use octal as hex is problematic reading back 
    printf("\\%03o", ch); 
    } 
} 

void EscapePrints(const char *data, int length) { 
    while (length-- > 0) { 
    EscapePrint((unsigned char) *data++); 
    } 
} 

可替換地,代碼可以

void EscapePrint(char sch) { 
    int ch = (unsigned char) sch; 
    ... 
} 
void EscapePrints(const char *data, int length) { 
    while (length-- > 0) { 
    EscapePrint(*data++); 
    } 
} 

要使用十六進制轉義序列或縮短八進制轉義序列,代碼需要確保該下一個字符不會產生歧義。在上面的代碼中不會出現這種複雜情況,因爲它使用3位八進制轉義序列。修正後的代碼會是這樣的:

} else { 
    if ((ch == 0) && (nextch < '0' || nextch > '7')) { 
     fputs("\\0", stdout); 
    } 
    else if (!isxdigit((unsigned char) nextch)) { 
     printf("\\x%X", ch); 
    } 
    else { 
     // Use octal as hex is problematic reading back 
     printf("\\%03o", ch); 
    } 
    }