standard c library for escaping a string

前端 未结 7 1943
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-10 17:51

Is there a standard C library function to escape C-strings?

For example, if I had the C string:

char example[] = \"first line\\nsecond line: \\\"inne         


        
相关标签:
7条回答
  • 2020-12-10 18:06
    while(*src++)
    {
      if(*src == '\\' || *src == '\"' || *src == '\'')
        *dest++ = '\\';
    
      *dest++ = *src++;
    }
    
    0 讨论(0)
  • 2020-12-10 18:08

    There is no standard C library function for this.

    When you use the declaration

    char example[] = "first line\nsecond line: \"inner quotes\"";
    

    the escape sequences will be interpreted and replaced by the compiler. You will have to "un-interpret" the characters that C escapes. Here's a quick-n-dirty example:

    #include <stdio.h>
    #include <ctype.h>
    
    void print_unescaped(char* ptr, int len) {
        if (!ptr) return;
        for (int i = 0; i < len; i++, ptr++) {
            switch (*ptr) {
                case '\0': printf("\\0");  break;
                case '\a': printf("\\a");  break;
                case '\b': printf("\\b");  break;
                case '\f': printf("\\f");  break;
                case '\n': printf("\\n");  break;
                case '\r': printf("\\r");  break;
                case '\t': printf("\\t");  break;
                case '\v': printf("\\v");  break;
                case '\\': printf("\\\\"); break;
                case '\?': printf("\\\?"); break;
                case '\'': printf("\\\'"); break;
                case '\"': printf("\\\""); break;
                default:
                    if (isprint(*ptr)) printf("%c",     *ptr);
                    else               printf("\\%03o", *ptr);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-10 18:08
    #include <string.h>    
    /* int c_quote(const char* src, char* dest, int maxlen)
     *
     * Quotes the string given so that it will be parseable by a c compiler.
     * Return the number of chars copied to the resulting string (including any nulls)
     *
     * if dest is NULL, no copying is performed, but the number of chars required to 
     * copy will be returned.
     *
     * maxlen characters are copied. If maxlen is negative, 
     * strlen is used to find the length of the source string, and the whole string
     * including the NULL-terminator is copied.
     *
     * Note that this function will not null-terminate the string in dest.
     * If the string in src is not null-terminated, or maxlen is specified to not
     * include the whole src, remember to null-terminate dest afterwards.
     *
     */
    int c_quote(const char* src, char* dest, int maxlen) {
        int count = 0;
        if(maxlen < 0) {
            maxlen = strlen(src)+1;      /* add 1 for NULL-terminator */
        }
    
        while(src  && maxlen > 0) {
            switch(*src) {
    
                /* these normal, printable chars just need a slash appended */
                case '\\':
                case '\"':
                case '\'':
                    if(dest) {
                        *dest++ = '\\';
                        *dest++ = *src;
                    }
                    count += 2;
                    break; 
    
                /* newlines/tabs and unprintable characters need a special code.
                 * Use the macro CASE_CHAR defined below.
                 * The first arg for the macro is the char to compare to,
                 * the 2nd arg is the char to put in the result string, after the '\' */
    #define CASE_CHAR(c, d) case c:\
        if(dest) {\
            *dest++ = '\\'; *dest++ = (d);\
            }\
    count += 2;\
    break;
                /* --------------  */
                CASE_CHAR('\n', 'n');
                CASE_CHAR('\t', 't');
                CASE_CHAR('\b', 'b');
                /*  ------------- */
    
    #undef CASE_CHAR
    
    
                /* by default, just copy the char over */
                default:
                    if(dest) {
                        *dest++ = *src;
                    }
                    count++;
            }
    
            ++src;
            --maxlen;
        }
        return count;
    }
    
    0 讨论(0)
  • 2020-12-10 18:19

    If you were writing GPL stuff you might use http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=lib/quotearg.c;hb=HEAD

    0 讨论(0)
  • 2020-12-10 18:21

    No standard C function, but not too hard to roll your own

    nothing too pretty but :-

    void escape_str(char *dest, char *src)
    {
         *dest = 0;
         while(*src)
         {
             switch(*src)
             {
                 case '\n' : strcat(dest++, "\\n"); break;
                 case '\"' : strcat(dest++, "\\\""); break;
                 default:  *dest = *src;
             }
             *src++;
             *dest++;
             *dest = 0;                     
         }
    }
    
    0 讨论(0)
  • 2020-12-10 18:21

    I felt like my previous answer was cheating because a function that writes to a buffer is much more useful than one that simply writes to stdout, so here's an alternative solution which works out how much memory one needs if dst is NULL, and also stops at dstLen as per the requirement.

    It's probably a little inefficient with all the if(dst) checking.

    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    
    size_t str_escape(char *dst, const char *src, size_t dstLen)
    {
        const char complexCharMap[] = "abtnvfr";
    
        size_t i;
        size_t srcLen = strlen(src);    
        size_t dstIdx = 0;
    
        // If caller wants to determine required length (supplying NULL for dst)
        // then we set dstLen to SIZE_MAX and pretend the buffer is the largest
        // possible, but we never write to it. Caller can also provide dstLen
        // as 0 if no limit is wanted.
        if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX;
    
        for (i = 0; i < srcLen && dstIdx < dstLen; i++)
        {
            size_t complexIdx = 0;
    
            switch (src[i])
            {
                case '\'':
                case '\"':
                case '\\':
                    if (dst && dstIdx <= dstLen - 2)
                    {
                        dst[dstIdx++] = '\\';
                        dst[dstIdx++] = src[i];
                    }
                    else dstIdx += 2;
                    break;
    
                case '\r': complexIdx++;
                case '\f': complexIdx++;
                case '\v': complexIdx++;
                case '\n': complexIdx++;
                case '\t': complexIdx++;
                case '\b': complexIdx++;
                case '\a':
                    if (dst && dstIdx <= dstLen - 2)
                    {
                        dst[dstIdx++] = '\\';
                        dst[dstIdx++] = complexCharMap[complexIdx];
                    }
                    else dstIdx += 2;
                    break;
    
                default:
                    if (isprint(src[i]))
                    {
                        // simply copy the character
                        if (dst)
                            dst[dstIdx++] = src[i];
                        else
                            dstIdx++;
                    }
                    else
                    {
                        // produce octal escape sequence
                        if (dst && dstIdx <= dstLen - 4)
                        {
                            dst[dstIdx++] = '\\';
                            dst[dstIdx++] = ((src[i] & 0300) >> 6) + '0';
                            dst[dstIdx++] = ((src[i] & 0070) >> 3) + '0';
                            dst[dstIdx++] = ((src[i] & 0007) >> 0) + '0';
                        }
                        else
                        {
                            dstIdx += 4;
                        }
                    }
            }
        }
    
        if (dst && dstIdx <= dstLen)
            dst[dstIdx] = '\0';
    
        return dstIdx;
    }
    
    0 讨论(0)
提交回复
热议问题