Is there an easy way to escape all special characters in the printf()
function?
The reason why I would like to know how to do this is because I am printing a number of characters which may include special characters such as the null character (\0
) and the beep character and I just want to see the contents of the string.
Currently I am using the following code
It works for null characters. What would be the easiest way to escape all special characters?
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 ] ) );
}
First of all, '\\0'
is a two-character literal, which should really be a two-character string. As for printing all special characters as escape code, you need some more code:
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;
}
Use the isprint
library function to determine if the character is printable:
#include <ctype.h>
...
if (isprint(data[i]))
printf(" %c", data[i]); // prints character
else
printf(" %d", data[i]); // prints code value for character
In case code needs to write with no ambiguity, using C syntax:
#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++);
}
}
Alternatively, code could
void EscapePrint(char sch) {
int ch = (unsigned char) sch;
...
}
void EscapePrints(const char *data, int length) {
while (length-- > 0) {
EscapePrint(*data++);
}
}
To use a hexadecimal-escape-sequence or a shorten octal-escape-sequence, code needs to insure that the next character does not create ambiguity. That complication does not occur in the above code as it uses 3-digit octal-escape-sequences. Amended code would be something like:
} 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);
}
}