2016-08-11 4 views
2

Скажем, у меня есть строка "file1.h: file2.c,file3.cpp", и я хочу, чтобы разбить его на "file1.h" и "file2.c,file3.cpp" - то есть с помощью : (: и пропуски) в качестве разделителя. Как мне это сделать?Разбивает строку, используя более чем один символ в качестве разделителя

Я попробовал этот код не поможет:

int main(int argc, char *argv[]) { 
    char str[] = "file1.h: file2.c,file3.cpp"; 
    char name[100]; 
    char depends[100]; 
    sscanf(str, "%s: %s", name, depends); 
    printf("Name: %s\n", name); 
    printf("Deps: %s\n", depends); 
} 

И выход я получаю:

Имя: file1.h:

Deps:

+1

Возможно, вы захотите проверить возвращаемое значение 'sscanf()' и считать, что ''% s '' * really * не соответствует '':'', как вы, кажется, предполагаете. – EOF

+1

': и backspace' .. вы уверены? –

+0

, если это ':' и '' (пробел), почему бы вам не попробовать 'strtok()'? он принимает больше, чем когда-то разграничитель, FWIW. –

ответ

2

То, что вам кажется, это strtok(). Читайте об этом в man page. Связанные цитаты из C11, глава §7.24.5.8

Последовательность вызовов функции strtok разбивает строку, на которую указывает s1 в последовательность лексем, каждый из которых разделителями персонажем из строки указывает на по s2. [...]

В вашем случае, вы можете использовать разделитель как

char * delim = ": "; //combination of : and a space 

идут получить работу.

Чем упомянуть дополнительно,

  • вход должен быть изменяемым (что, в вашем случае) для strtok()
  • и фактически уничтожает вход подводимой к нему, сохранить копию вокруг, если вам нужно фактическое позже.
+0

Да! Большое спасибо за ваши усилия! Оно работает. – Vipasana

+1

Обратите внимание, что 'strtok()' имеет много проблем. Вместо этого я рекомендую 'strpbrk()'. Он не реентерабелен, не потокобезопасен, он сконструирован таким образом, что он запутывается, передавая «NULL» после первого раза и т. Д. Он изменяет входную строку. Это отстой. –

1

Как говорит Сурав, вам необходимо использовать strtok для токенизирующих строк. Но это не объясняет , почему ваш существующий код не работает.

Ответ лежит в спецификации для sscanf и как он обрабатывает код '%s' в строке формата.

С man страницы:

s Соответствует последовательности без пробельных символов;

Таким образом, наличие пробела в строке форматирования в значительной степени не имеет отношения к математике первого '%s'. Когда sscanf видит первый номер , он просто потребляет входную строку до тех пор, пока не встретится символ пробела, предоставив вам ваше значение для name из "file1.h:" (обратите внимание на включение двоеточия).

Затем он пытается разобраться с последовательностью пробелов в строке форматирования.

Опять же, из man страницы

Строка формата состоит из последовательности директив, которые описывают, как обрабатывать последовательность входных символов.

Последовательность двоеточия пробела не соответствует какой-либо известной директиве (т. Е. «%», За которой следует что-то), и таким образом вы получите соответствующий сбой.

Если вместо этого ваша строка формата была просто "%s%s", тогда sscanf доставит вам почти то, что вы хотите.

int main(int argc, char *argv[]) { 
    char str[] = "file1.h: file2.c,file3.cpp"; 
    char name[100]; 
    char depends[100]; 
    sscanf(str, "%s%s", name, depends); 
    printf("str: '%s'\n", str); 
    printf("Name: %s\n", name); 
    printf("Deps: %s\n", depends); 
    return 0; 
} 

Что дает этот вывод:

str: 'file1.h: file2.c,file3.cpp' 
Name: file1.h: 
Deps: file2.c,file3.cpp 

На данный момент, вы можете просто проверить, что sscanf дал возвращаемое значение 2 (т.е. он нашел два значения), и что последний символ name это двоеточие. Затем просто усекайте name, и у вас есть свой ответ.

Конечно, по этой логике, вы не собираетесь быть в состоянии использовать sscanf разобрать вашу depends переменную в несколько строк ... поэтому другие рекомендуют с помощью strtok, strpbrk и т.д., потому что вы оба синтаксического анализа и токенизируя ваш вход.

1

Это альтернативный способ сделать это, он использует strchr(), но это предполагает, что входная строка всегда имеет формат

name: item1,item2,item3,...,itemN 

Вот программа

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

int 
main(void) 
{ 
    const char *const string = "file1.h: file2.c,file3.cpp "; 

    const char *head; 
    const char *tail; 
    const char *next; 

    // This basically makes a pointer to the `:' 
    head = string; 
    // If there is no `:' this string does not follow 
    // the assumption that the format is 
    // 
    // name: item1,item2,item3,...,itemN 
    //  
    if ((tail = strchr(head, ':')) == NULL) 
     return -1; 
    // Save a pointer to the next character after the `:' 
    next = tail + 1; 
    // Strip leading spaces 
    while (isspace((unsigned char) *head) != 0) 
     ++head; 
    // Strip trailing spaces 
    while (isspace((unsigned char) *(tail - 1)) != 0) 
     --tail;  

    fputc('*', stdout); 
    // Simply print the characters between `head' and `tail' 
    // you could as well copy them, or whatever 
    fwrite(head, 1, tail - head, stdout); 
    fputc('*', stdout); 
    fputc('\n', stdout); 

    head = next; 
    while (head != NULL) {  
     tail = strchr(head, ','); 
     if (tail == NULL) { 
      // This means there are no more `,' 
      // so we now try to point to the end 
      // of the string 
      tail = strchr(head, '\0'); 
     } 
     // This is basically the same algorithm 
     // just with a different delimiter which 
     // will presumably be the same from 
     // here 
     next = tail + 1; 
     // Strip leading spaces 
     while (isspace((unsigned char) *head) != 0) 
      ++head; 
     // Strip trailing spaces 
     while (isspace((unsigned char) *(tail - 1)) != 0) 
      --tail;  
     // Here is where you can extract the string 
     // I print it surrounded by `*' to show that 
     // it's stripping white spaces 
     fputc('*', stdout); 
     fwrite(head, 1, tail - head, stdout); 
     fputc('*', stdout); 
     fputc('\n', stdout); 
     // Try to point to the next one 
     // or make head `NULL' if this is 
     // the end of the string 
     // 
     // Note that the original `tail' pointer 
     // that was pointing to the next `,' or 
     // the end of the string, has changed but 
     // we have saved it's original value 
     // plus one, we now inspect what was 
     // there 
     if (*(next - 1) == '\0') { 
      head = NULL; 
     } else { 
      head = next; 
     } 
    } 
    fputc('\n', stderr); 
    return 0; 
} 

Это слишком комментировал к направляйте читателя.

0

Хорошо, я довольно поздно. У меня не так много знаний о встроенных функциях в C. Поэтому я начал писать решение для вас. Я не думаю, что тебе нужно это сейчас. Но, в любом случае here it is и измените его в соответствии с вашими потребностями. Если вы обнаружите ошибку, не стесняйтесь сказать.