Escape all special characters in printf()

前端 未结 4 1559
遇见更好的自我
遇见更好的自我 2020-12-07 04:24

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 print

相关标签:
4条回答
  • 2020-12-07 05:02

    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
    
    0 讨论(0)
  • 2020-12-07 05:06

    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);
        }
      }
    
    0 讨论(0)
  • 2020-12-07 05:09
    #include <stdio.h>
    #include <ctype.h>
    
    
    /* Converts a buffer of specified lenth to
     * ASCII representation as it was a C string literal.
     * Returns how much bytes from source was processed
     * (ideally ret == src_sz)
     */
    int binbuf_to_escaped_C_literal(const char *src_buf, size_t src_sz, char *dst_str, size_t dst_sz)
    {
        const char *src = src_buf;
        char *dst = dst_str;
    
        while (src < src_buf + src_sz)
        {
            if (*src == '\\')
            {
                *dst++ = '\\';
                *dst++ = *src++;
            }
            else if (isprint(*src))
            {
                *dst++ = *src++;
            }
            else
            {
                switch(*src)
                {
                    case '\n':
                        *dst++ = '\\';
                        *dst++ = 'n';
                        break;
                    case '\r':
                        *dst++ = '\\';
                        *dst++ = 'r';
                        break;
                    case '\t':
                        *dst++ = '\\';
                        *dst++ = 't';
                        break;
                    case '\0':
                        *dst++ = '\\';
                        *dst++ = '0';
                        break;
                    default:
                        sprintf(dst, "0x%x", *src);
                        dst += 4;
                }
                src++;
            }
    
            // next iteration requires up to 5 chars in dst buffer, for ex.  "0xab\0"
            if (dst > (dst_str + dst_sz - 5)) {
                break;
            }
        }
    
        *dst = '\0';
    
        return src - src_buf;
    }
    
    
    int main(int argc, char **argv)
    {
        const char binbuf[] = "strange \n\r\t\0\0\0\0\0\\\\ string";
        size_t sz = sizeof(binbuf) - 1; // drop trailing nul terminator
    
        char escaped[128];
    
        if (binbuf_to_escaped_C_literal(binbuf, sz, escaped, sizeof(escaped)) != sz) {
            fprintf(stderr, "Destination string buffer is too small\n");
            return 1;
        }
    
        printf("Escaped: %s\n", escaped);
    
        // $ ./escape-binary-buf                                          //
        // Escaped: strange \n\r\t\0\0\0\0\0\\\\ string                   //
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-07 05:17

    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;
    }
    
    0 讨论(0)
提交回复
热议问题