Преобразуйте символы в строке ac в их escape-последовательности - PullRequest
5 голосов
/ 21 августа 2010

Мне нужна функция типа string ToLiteral (строковый ввод) из этого поста .Такой, что

char *literal = to_literal("asdf\r\n");

даст literal ==> "asdf \\ r \\ n" .

Я гуглил, но не смогнайти что-нибудь (думаю, что я, должно быть, использовал неправильные термины).Тем не менее, я предполагаю, что библиотека с этой функциональностью должна быть где-то там ...

Спасибо за интересные ответы.Похоже, поиск «функции побега строки c» является ключом к получению еще большего количества примеров, и GLIB предоставляет g_strescape (), который, кажется, является именно тем, что мне нужно.

Ответы [ 3 ]

8 голосов
/ 21 августа 2010

Для этого нет встроенной функции, но вы могли бы ее поднять:

/* Expands escape sequences within a C-string
 *
 * src must be a C-string with a NUL terminator
 *
 * dest should be long enough to store the resulting expanded
 * string. A string of size 2 * strlen(src) + 1 will always be sufficient
 *
 * NUL characters are not expanded to \0 (otherwise how would we know when
 * the input string ends?)
 */

void expand_escapes(char* dest, const char* src) 
{
  char c;

  while (c = *(src++)) {
    switch(c) {
      case '\a': 
        *(dest++) = '\\';
        *(dest++) = 'a';
        break;
      case '\b': 
        *(dest++) = '\\';
        *(dest++) = 'b';
        break;
      case '\t': 
        *(dest++) = '\\';
        *(dest++) = 't';
        break;
      case '\n': 
        *(dest++) = '\\';
        *(dest++) = 'n';
        break;
      case '\v': 
        *(dest++) = '\\';
        *(dest++) = 'v';
        break;
      case '\f': 
        *(dest++) = '\\';
        *(dest++) = 'f';
        break;
      case '\r': 
        *(dest++) = '\\';
        *(dest++) = 'r';
        break;
      case '\\': 
        *(dest++) = '\\';
        *(dest++) = '\\';
        break;
      case '\"': 
        *(dest++) = '\\';
        *(dest++) = '\"';
        break;
      default:
        *(dest++) = c;
     }
  }

  *dest = '\0'; /* Ensure nul terminator */
}

Обратите внимание, что я пропустил перевод escape-последовательности для символа escape, поскольку она не стандартизирована в C (некоторые компиляторы используют \e, а другие - \x). Вы можете добавить в зависимости от того, что относится к вам.

Если вам нужна функция, которая выделяет вам буфер назначения:

/* Returned buffer may be up to twice as large as necessary */
char* expand_escapes_alloc(const char* src)
{
   char* dest = malloc(2 * strlen(src) + 1);
   expand_escapes(dest, src);
   return dest;
}
1 голос
/ 21 августа 2010

Я думаю, я бы сделал преобразование примерно так:

// warning: untested code.
void make_literal(char const *input, char *output) { 
    // the following two arrays must be maintained in matching order:
    static char inputs[] = "\a\b\f\n\r\t\v\\\"\'";
    static char outputs[] = "abfnrtv\\\"\'";

    char *p, *pos;

    for (;*input;input++) {
        if (NULL!= (pos=strchr(inputs, *input))) {
            *output++ = '\\';
            *output++ = outputs[pos-inputs];
        }
        else
            *output++ = *input;
    }
    *output = '\0';
}

Теоретически, это может быть немного медленнее, чем (для одного примера) кода Тайлера МакГенри. В частности, его использование оператора switch позволяет (но не требует) постоянного выбора правильного пути. В действительности, учитывая разреженность задействованных значений, вы, вероятно, не получите постоянный выбор времени, а задействованная строка настолько коротка, что в любом случае разница обычно будет довольно небольшой. В другом направлении, я ожидал бы, что это будет легче поддерживать (например, если вы хотите поддерживать больше escape-последовательностей, добавлять их должно быть довольно легко, пока форма остается постоянной).

0 голосов
/ 21 августа 2010

Я думаю, что вы путаете терминологию, вы можете инициализировать указатель на символ (acter) следующим образом:

char *literal = "asdf\r\n"

Поправка: Однако строки C могут использовать escapeкавычки, например:

char *literal = "\basdf\x1b\r\n\v\t";

Это будет выводить

<backspace>asdf<escape-character><carriage-return><linefeed><vertical-tab><tab>

Эти символы не будут отображаться в зависимости от возможностей консоли, вы можете увидеть стрелку для перехода и пробелдля вкладки ... вы можете обойти это, используя простую логику, для каждого \ вставьте еще один \ так, чтобы он отображал

asdf\\r\\n

что-то вроде следующего кода должно быть достаточно:

void ToLiteral(const char *pStr){
    char *p = (char*)pStr;
    while (*p){
       /* if (*p == '\\') putchar('\\');  */
       /* PERFORM THE LOOK UP */
       putchar(*p++);
    }
}

Но, глядя на это, он не чувствовал себя правильно, так как указатель содержал фактические \n и \r, поэтому может быть проще использовать справочную таблицу, которая сравнивает фактическиешестнадцатеричный код для escape-последовательностей и для отображения соответствующего кода ... таблица поиска может выглядеть примерно так:

struct LookUp{
    int codeLiteral;
    char *equivCodeLiteral;
};

struct LookUp look[] = { { 0xa, "\\r"}, { 0xd, "\\n" }, { 0x9, "\\t" } };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...