C - извлечение слов из строки - PullRequest
2 голосов
/ 09 марта 2012

Я довольно новичок в C и поэтому столкнулся с некоторой путаницей при использовании указателей.

Я пытаюсь извлечь слова из строки символов ASCII. Например, если у меня есть строка @@ Hello..world >>, я хочу вывести слова «Hello» и «world» из строки и добавить их в мой связанный список.

Слово определяется как любая последовательность букв, и каждое слово не может превышать 64 байта. Кроме того, любой символ, в котором функция isspace () возвращает ненулевое значение, считается пробелом.

По сути, я сканирую строки из файла, используя fscanf, затем для каждой строки вызываю мою функцию read_words (char * s), чтобы вывести нужные слова из строки и добавить их в мой связанный список для дальнейшего использования. ,

Вот мой код, который, кажется, выдает ошибку, связанную с указателем.

struct node {
    char *val;
    struct node *next;
    int count;
} *words = NULL;


void read_words(char *s)
{
    struct node *tmp;
    char word[64+1];
    int i, check, wordStarted = 0, count = 0;

    for (i = 0; s[i] != '\0'; i++)
    {
            if ((isspace(s[i]) != 0) || !isalpha(s[i]))
            {
                    if (wordStarted == 1)
                    {
                            check = check_list(word);
                            if (check != 1) {
                                    word[count] = '\0';
                                    tmp = malloc(sizeof(struct node));
                                    tmp->val = word;
                                    tmp->count = 1;
                                    tmp->next = words;
                                    words = tmp;
                            }
                            count = 0;
                            wordStarted = 0;
                    }
            }
            else
            {
                    word[count++] = s[i];
                    wordStarted = 1;
            }
    }

}

Любая помощь с этим будет высоко ценится!

Спасибо!

Ответы [ 2 ]

6 голосов
/ 09 марта 2012

Вы захотите токенизировать строку вместо реализации собственного алгоритма и добавить части в свой связанный список. Используйте strtok ( ref ).

По ссылке выше .. пример:

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

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

Выход:

Splitting string "- This, a sample string." into tokens:
This
a
sample
string
1 голос
/ 20 декабря 2016

Лучшее решение для ANSI C.

Использование strtok () это не всегда хорошо:

  1. это изменит исходный массив.
  2. Разделитель пробела "" игнорирует похожие символы: "\ n", "\ t" и др.

Попробуйте следующий и прочитайте комментарии для деталей:

#include <stdio.h>      // printf
#include <string.h>     // strlen, strncpy
#include <ctype.h>      // isalnum
#include <stdlib.h>     // malloc, calloc

/*
    A logical type
 */
typedef enum {
    false,
    true,
} bool;


/*
    A Struct for hold 2D-array with count items
 */
typedef struct _ListWithLength {
    char **list;
    size_t length;
} ListWithLength;


/*
    Parse a text and return pointer to a ListWithLength words and count it
 */
ListWithLength* getWords(char *text) {

    // a variable for count words
    int count = 0;

    // keep length of the text
    size_t text_len = strlen(text);

    // a flag indicating the a beginning of a word
    bool new_word = false;

    // an index of a start found a word
    int index_start_word = 0;

    // 2D-array for found word
    // it will be same memory size as the original text
    char **words = malloc(text_len * sizeof(char));

    for (int i = 0; i <= text_len; ++i) {

        // if found ascii letter or digits and new no traced early
        // keep index of beginning a new word
        // and change the flag
        if (isalnum(text[i]) != 0) {
            if (new_word == false) {
                new_word = true;
                index_start_word = i;
            }

        // if it is not ascii letter or digits and a word traced early
        // it means the word ended
        } else {
            if (new_word == true) {

                // allocate a memory for a new word in the array of words
                words[count] = malloc(i - index_start_word * sizeof(char) + 1);

                // copy the found word from the text by indexes
                strncpy(words[count], text + index_start_word, i - index_start_word);

                // change the flag
                new_word = false;

                // increase the counter of words
                count++;
            }
        };
    }

    // bind the found words and it count to a structure and return it
    ListWithLength *list_with_length = malloc(sizeof(ListWithLength));

    list_with_length->length = count;
    list_with_length->list = words;

    return list_with_length;
}


/*
    Print information of a ListWithLength
 */
void printListWithLength(ListWithLength *list_with_length) {
    printf("Total items: %li\n", list_with_length->length);
    puts("----------------------");
    for (int i = 0; i < list_with_length->length; ++i) {
        printf("%d. %s\n", i + 1, list_with_length->list[i]);
    }
}


int main(int argc, char const *argv[])
{

    char c_keywords[300] = "auto else    long    switch\
    break\t   enum \t register    typedef\
    \ncase    extern,  return  union\
    ?char    float.   short   unsigned\
    const   !for signed  void\
    continue    goto    sizeof  volatile\
    .default???? if  static  while\
    do  int struct,,,,  _Packed\
    double.......";

    ListWithLength *list_with_length = getWords(c_keywords);
    printListWithLength(list_with_length);

    return 0;
}

Скомпилируйте и посмотрите результат:

$ gcc -Wall -ansi -std=c11 -o main main.c
$ ./main 
Total items: 33
----------------------
1. auto
2. else
3. long
4. switch
5. break
6. enum
7. register
8. typedef
9. case
10. extern
11. return
12. union
13. char
14. float
15. short
16. unsigned
17. const
18. for
19. signed
20. void
21. continue
22. goto
23. sizeof
24. volatile
25. default
26. if
27. static
28. while
29. do
30. int
31. struct
32. Packed
33. double
...