2015-04-13 3 views
0

Мне было интересно, мы будем делиться нитями в токенах или любыми другими эффективными способами.Разбиение строк на языке C

то у меня есть ...

char string1[] = "hello\tfriend\n"; 

Как бы я получить «привет» и «друга» в своих собственных отдельных переменных?

+1

Возможный дубликат [Сплит-строка с разделителями в C] (http://stackoverflow.com/questions/9210528/split-string-with-delimiters-in-c) –

+0

Существует 2 основных способа: (1) с 'strtok' или (2) использование простого указателя для определения начала каждого слова и символа разделителя, следующего за словом. –

ответ

2

Вот очень простой пример, разбивающий вашу строку на части, сохраненные в массиве массивов символов, используя указатель начала и конца. В MAXL и MAXW определяет просто удобный способ, чтобы определить константы, которые используются для ограничения индивидуальной длины слова до 32 (31 символов + нуль-терминатор) и максимум 3 слов (частей) исходной строки:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define MAXL 32 
#define MAXW 3 

int main (void) { 

    char string1[] = "hello\tfriend\n"; 
    char *sp = string1;     /* start pointer  */ 
    char *ep = string1;     /* end pointer   */ 
    unsigned c = 0;      /* temp character  */ 
    unsigned idx = 0;     /* index for part  */ 
    char strings[MAXW][MAXL] = {{0}}; /* array to hold parts */ 

    while (*ep)       /* for each char in string1 */ 
    { 
     if (*ep == '\t' || *ep == '\n') /* test if \t or \n   */ 
     { 
      c = *ep;     /* save character   */ 
      *ep = 0;     /* replace with null-termator */ 
      strcpy (strings[idx], sp); /* copy part to strings array */ 
      *ep = c;     /* replace w/original character */ 
      idx++;      /* increment index   */ 
      sp = ep + 1;    /* set start pointer  */ 
     } 
     ep++;       /* advance to next char  */ 
    } 

    printf ("\nOriginal string1 : %s\n", string1); 

    unsigned i = 0; 
    for (i = 0; i < idx; i++) 
     printf (" strings[%u] : %s\n", i, strings[i]); 

    return 0; 
} 

Выход

$ ./bin/split_hello 

Original string1 : hello  friend 

    strings[0] : hello 
    strings[1] : friend 

Использование strtok просто заменяет ручной указатель логики с вызовом функции, чтобы разделить строку.


Обновлено завершений строк Обработка Пример

Как вы нашли, когда шаговый хотя строка, которую вы можете создать простой пример, как вам нужно, чтобы соответствовать текущей строке, но с немного больше вы можете расширить свой код, чтобы справиться с более широким спектром ситуаций. В вашем комментарии вы отметили, что приведенный выше код не обрабатывает ситуацию, когда в конце строки нет newline. Вместо того, чтобы менять код, чтобы справиться с этой ситуацией, с небольшим размышлением вы можете улучшить код, чтобы он обрабатывал обе ситуации. Один из возможных подходов:

while (*ep)       /* for each char in string1 */ 
    { 
     if (*ep == '\t' || *ep == '\n') /* test if \t or \n   */ 
     { 
      c = *ep;     /* save character   */ 
      *ep = 0;     /* replace with null-termator */ 
      strcpy (strings[idx], sp); /* copy part to strings array */ 
      *ep = c;     /* replace w/original character */ 
      idx++;      /* increment index   */ 
      sp = ep + 1;    /* set start pointer  */ 
     } 
     else if (!*(ep + 1)) {   /* check if next is ending */ 
      strcpy (strings[idx], sp); /* handle no ending '\n' */ 
      idx++; 
     } 

     ep++;       /* advance to next char  */ 
    } 

Перерыв на любой Формат/непечатных символов

Продолжая расширять символы, которые могут быть использованы для разделения строк, а не использовать дискретные значения для идентификации какие символы делят слова, вы можете использовать диапазон значений ASCII для идентификации всех непечатаемых или форматированных символов в качестве разделителей. Несколько иной подход может быть использован:

char string1[] = "\n\nhello\t\tmy\tfriend\tagain\n\n"; 
    char *p = string1;     /* pointer to char  */ 
    unsigned idx = 0;     /* index for part  */ 
    unsigned i = 0;      /* generic counter  */ 
    char strings[MAXW][MAXL] = {{0}}; /* array to hold parts */ 

    while (*p)       /* for each char in string1 */ 
    { 
     if (idx == MAXW) {    /* test MAXW not exceeded */ 
      fprintf (stderr, "error: MAXW (%d) words in string exceeded.\n", MAXW); 
      break; 
     } 

     /* skip each non-print/format char */ 
     while (*p && (*p < ' ' || *p > '~')) 
      p++; 

     if (!*p) break;     /* if end of s, break  */ 

     while (*p >= ' ' && *p <= '~') /* for each printable char */ 
     { 
      strings[idx][i] = *p++;  /* copy to strings array */ 
      i++;      /* advance to next position */ 
     } 

     strings[idx][i] = 0;   /* null-terminate strings */ 
     idx++;       /* next index in strings */ 
     i = 0;       /* start at beginning char */ 
    } 

Это будет обрабатывать тестовую строку независимо от линии прекращения и независимо от количества вкладок или переводов строк включены. Взгляните на ASCII Table and Description в качестве ссылки на используемые диапазоны символов.

+0

Обратите внимание, что вы не можете надежно использовать 'strtok()' в строковых литералах, поскольку он изменяет строку, которую он анализирует, и строковые литералы часто не изменяются. –

+0

Ну, да. Вы также должны были сделать копию строки сначала, чтобы не допустить, чтобы ваш оригинал был завален символами с нулевым завершением. Хорошая точка зрения. –

+0

Привет, я попробовал ваше предложение, и мне было интересно, что, если текст был просто «hello \ tfriend». Когда я попытался сделать строки [1], это не получилось. Благодаря! – Antwon

Смежные вопросы