2010-04-27 9 views
6

¿Hay una función estándar de biblioteca de C para escapar C-cuerdas?biblioteca C estándar para escapar de una cadena

Por ejemplo, si tuviera la cadena C:

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

Y quería imprimir

"first line\nsecond line: \"inner quotes\"" 

¿Hay una función de biblioteca que va a hacer que la transformación para mí? Rodar por mi cuenta me parece un poco tonto.

Los puntos de bonificación si puedo darle una longitud de escapar (por lo que se detiene antes o más allá de la \0).

+0

Detener más allá del '\ 0' parece peligroso, es mejor estar 100% seguro de que la longitud es válida o se producirá el caos. – bta

+0

útil aunque cuando quiero mostrar algunos datos binarios de forma segura. – rampion

Respuesta

0

Sin función estándar de C, pero no demasiado difícil de rodar su propia

nada demasiado bonita, pero: -

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

He revocado el voto que he dado cuando su respuesta no tenía código ... –

+0

ok .............. –

-2
while(*src++) 
{ 
    if(*src == '\\' || *src == '\"' || *src == '\'') 
    *dest++ = '\\'; 

    *dest++ = *src++; 
} 
+0

este código carece de \ r \ n \ f \ a \ b \ t y otros nonprintables handling –

+0

no se olvide de las comillas dobles iniciales y finales, verificando 'isprint()' y produciendo los escapes apropiados para los no imprimibles comunes y espacios en blanco ('\ n',' \ t') y octal escapes para los demás ('\ 0 ',' \ 377'). – rampion

+0

que no funcionará ya que los caracteres de escape en realidad no entran en la cadena –

1

Acabas de mencionar que querías imprimir la cadena.

char example[] = "first line\nsecond line: \"inner quotes\""; 
size_t len = strlen(example); 
size_t i; 

static const char *simple = "\\\'\""; 
static const char *complex = "\a\b\f\n\r\t\v"; 
static const char *complexMap = "abfnrtv"; 

for (i = 0; i < length; i++) 
{ 
    char *p; 
    if (strchr(simple, example[i])) 
    { 
     putchar('\\'); 
     putchar(example[i]); 
    } 
    else if ((p = strchr(complex, example[i])) 
    { 
     size_t idx = p - complex; 
     putchar('\\'); 
     putchar(complexMap[idx]); 
    } 
    else if (isprint(example[i])) 
    { 
     putchar(example[i]); 
    } 
    else 
    { 
     printf("\\%03o", example[i]); 
    } 
} 
+0

¿Qué pasa con otras no imprimibles? \ 033, por ejemplo? –

+0

@Michael Krelin: no probado, pero ahora imprime no imprimibles como octal escapes. – dreamlax

+1

Usted obtiene mi voto como el primero y solo quienes realmente tomaron son del problema ;-) –

2

No existe una función de biblioteca C estándar para esto.

Cuando se utiliza la declaración

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

las secuencias de escape se interpretarán y se sustituyen por el compilador. Tendrás que "des-interpretar" los caracteres que C escapa. Aquí está un ejemplo sucia rápida-n-:

#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); 
     } 
    } 
} 
+1

No estoy seguro de estar al tanto, pero 'puts' agrega una nueva línea al final. – dreamlax

+0

¿qué diablos es 'else' para un' interruptor'? –

+0

¡Ja! Eso me lleva de vuelta a los días VB con 'Select Case' y 'Case Else'. – dreamlax

0
#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

sentí que mi respuesta anterior estaba engañando porque una función que escribe en un buffer es mucho más útil que uno que simplemente escribe a stdout, así que aquí tiene una solución alternativa que se resuelve la cantidad de memoria que se necesita si es dstNULL, y también se detiene en dstLen como por la exigencia.

Es probablemente un poco ineficiente con toda la comprobación if(dst).

#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; 
} 
Cuestiones relacionadas