C извлекать слова из текстового файла, кроме пробелов и знаков препинания

Я пытаюсь извлечь слова из файла .txt, который содержит следующее предложение

Quando avevo cinqve anni, mia made mi perpeteva sempre che la felicita e la chiave della vita. Quando andai a squola mi domandrono come vuolessi essere da grande. Io scrissi: selice. Mi dissero che non avevo capito il corpito, e io dissi loro che non avevano capito la wita.

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

Я знаю, что такие вещи, как «пустые слова» или «пустые символы» не имеют смысла, но попробуйте код с текстом, который я передал, и вы все поймете.

Тем временем я пытаюсь понять использование sscanf с этим модификатором sscanf(buffer, "%[^.,:]");, который должен позволить мне хранить строки, игнорируя символы ., , и :, однако я не знаю, что i должен писать в %[^], чтобы игнорировать пустой символ ' ', который всегда спасается.

Код следующий

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

static void load_array(const char* file_name){
  char buffer[2048];
  char a[100][100];
  int buf_size = 2048;
  FILE *fp;
  int j = 0, c = 0;

  printf("\nLoading data from file...\n");

  fp = fopen(file_name,"r"); 

  if (fp == NULL){
    fprintf(stderr,"main: unable to open the file");
    exit(EXIT_FAILURE);
  }

  fgets(buffer,buf_size,fp);

  //here i store each word in an array of strings when I encounter 
  //an unwanted char I save the word into the next element of the 
  //array    
  for(int i = 0; i < strlen(buffer); i++) {    

    if ((buffer[i] >= 'a' && buffer[i] <= 'z') || (buffer[i] >= 'A' && buffer[i] <= 'Z')) {
        a[j][c++] = buffer[i];  
    } else {
        j++;
        c = 0;
        continue;
    }
  }

  //this print is used only to see the words in the array of strings
  for(int i = 0; i < 100; i++) 
    printf("%s  %d\n", a[i], i);

  fclose(fp);
  printf("\nData loaded\n");
}

//Here I pass the file_name from command line
int main(int argc, char const *argv[]) {
  if (argc < 2) {
    printf("Usage: ordered_array_main <file_name>\n");
    exit(EXIT_FAILURE);
  }

  load_array(argv[1]);

}

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

Составление и исполнение

gcc -o testloadfile testloadfile.c

./testloadfile "correctme.txt"

Вы забыли добавить последний '\ 0' в каждую строку a. И ваш алгоритм имеет много недостатков (например, как вы увеличиваете j каждый раз, когда появляется не буква. Что, если у вас есть ","? Вы увеличиваете два раза вместо одного). Советую посмотреть "стрток"

Tom's 18.04.2018 12:45

И здесь может помочь использование отладчика.

Jabberwocky 18.04.2018 12:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
658
2

Ответы 2

вместо этого вы можете попробовать использовать strtok

fgets(buffer,buf_size,fp);
for (char* tok = strtok(buffer,".,: "); *tok; tok = strtok(NULL,".,: "))
{
   printf("%s\n", tok);
}

Примечание: если вы хотите сохранить то, что возвращает strtok, вам нужно либо скопировать содержимое того, на что указывает tok, либо выделить копию с помощью strdup / malloc + strcpy, поскольку strtok изменяет свою копию первого аргумента при анализе строки.

Нет, strtok не пропускает автоматически пустое пространство (с каких это пор?). Более того, ваш код ложный (отсутствует ')' в конце цикла for).

Tom's 18.04.2018 13:05

@ Tom's, как я могу пропустить пустое место, если strtok этого не делает?

Zeno Raiser 18.04.2018 13:34

Добавив '' в разделитель strtok.

Tom's 18.04.2018 13:46

Вы забыли добавить последний '\0' в каждую строку a, и ваш алгоритм имеет много недостатков (например, как вы увеличиваете j каждый раз, когда появляется не-буква. Что, если у вас есть ", "? Вы увеличиваете два раза вместо одного).

Один из «простых» способов - использовать strtok, как показывает вам Андерс К..

fgets(buffer,buf_size,fp);
for (char* tok = strtok(buffer,".,:"); *tok; tok = strtok(NULL,".,:")) {
   printf("%s\n", tok);
}

«Проблема» этой функции в том, что вам нужно указать весь разделитель, поэтому вам нужно добавить ' ' (пробел), '\t' (табуляция) и т. д.

Поскольку вам нужно только "слово", как описано как "содержать только букву, минускул или маюскуле", вы можете сделать следующее:

int main(void)
{
    char line[] = "Hello ! What a beautiful day, isn't it ?";

    char *beginWord = NULL;

    for (size_t i = 0; line[i]; ++i) {
        if (isalpha(line[i])) { // upper or lower letter ==> valid character for a word
            if (!beginWord) {
                // We found the beginning of a word
                beginWord = line + i;
            }
        } else {
            if (beginWord) {
                // We found the end of a word
                char tmp = line[i];
                line[i] = '\0';
                printf("'%s'\n", beginWord);
                line[i] = tmp;
                beginWord = NULL;
            }
        }
    }

    return (0);
}

Обратите внимание, как «not» делится на «isn» и «t», поскольку ' не является подходящим символом для вашего слова.

Алгоритм довольно прост: мы просто зацикливаем строку, и если это допустимая буква и beginWord == NULL, то это начало слова. Если это неверная буква и beginWord != NULL, то это конец слова. Тогда вы можете иметь любое количество букв между двумя словами, вы все равно можете четко определить слово.

Другие вопросы по теме