Скопировать содержимое, ограничив длину строки N символами - C (СИ)

Узнай цену своей работы

Формулировка задачи:

Всем доброго времени суток, нужна помощь с задачей: "Скопировать содержимое текстового файла, ограничив длину строки N символами. Слова, не помещающиеся в заданную строку не копировать." Поработав с программами, найденными в интернете получил две разные программы: 1)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define LEN_STR  1024
#define N        5
 
char  seps[10] = " ,.!?:;'\n";
char* text;
char* temp;
FILE* source;
FILE* target;
 
void main(void)
{
    source = fopen("1.txt", "rt");
    target = fopen("2.txt", "wt");
    text   = (char*)calloc(LEN_STR, 1);
    temp   = (char*)calloc(LEN_STR, 1);
 
    while (!feof(source))
    {
        fgets(text, LEN_STR, source);
        strncpy(temp, text, N);
        if (strlen(text) > N)
        {
            temp[N] = '\n';
            temp[N + 1] = 0;
        }
        fputs(temp, target);
    }
 
    fclose(source);
    fclose(target);
    free(text);
    free(temp);
}
2)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#define MAXLEN 4        //Макс. длина строки
 
int main(void)
{
    char c=0;    //Хранится символ из входного файла, вспомогательная переменная
    char String[MAXLEN + 1];
 
    char *pathFileInput=(char*)calloc(20, sizeof(char));
    char *pathFileOutput=(char*)calloc(20, sizeof(char));
    FILE *fileInput;    //Файловая переменная для входного файла
    FILE *fileOutput;    //Файловая переменная для выходного файла
 
    fileInput=fopen("1.txt",  "rt");
    fileOutput= fopen("2.txt", "wt");
    while(c!=EOF)
    {
        fgets(String,MAXLEN + 1,fileInput);
        fputs(String,fileOutput);
        fputc('\n', fileOutput);
        while (c != '\n' && c != EOF)
            c = fgetc(fileInput);

        if (c!=EOF) //Если это не признак конца файла, c = пробел (или любой другой неслужебный символ
            c=' '; //иначе мы застрянем во вложенном while на след. итерации
    }
 
    free(pathFileInput);
    free(pathFileOutput);
    fclose (fileInput);
    fclose(fileOutput);
    return 0;
}
И всё бы ничего, но обе программы просто обрывают слова на середине, если эти слова не влезают в длину, а нужно, чтобы если слово не помещалось, то оно целиком и полностью удалялось. Посидев, пораскинув мозгами прикинул следующую схему: 1) Копируем текстовый документ 1.txt, работаем с каждой строкой по очереди; 2) В общем цикле для работы с каждой строкой: Разбивать строку на слова, слова заносить в массив, а дальше в цикле сравнивать длину i первых слов в массиве (с пробелами) с числом N. Если i < N, то идти дальше. Если i > N, то если кол-во слов больше одного, то записывать [i-1] слов из массива в строку и переходить к следующей строке. Ну или как-то так. На словах, как говорится, Лев Толстой... А время поджимает. Попробовав реализовать, понял, что проблема в моих знаниях и опыте. Буду очень благодарен, если доделаете мою программу или предложите свой вариант. Мои наработки:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define LEN_STR  1024
#define N        5
 
char  seps[10] = " ,.!?:;'\n";
char* text;
char* temp;
char* word;
 
FILE* source;
FILE* target;
 
char* data[100];
 
void main(void)
{
    source = fopen("1.txt", "rt");
    target = fopen("2.txt", "wt");
    text   = (char*)calloc(LEN_STR, 1);
    temp   = (char*)calloc(LEN_STR, 1);
 
    while (!feof(source))
    {
        fgets(text, LEN_STR, source);
 
        //Заимствуем код из программы, удаляющей слова, больше определённого размера
        //last = temp;
        //word = strtok(temp, seps);
        //while (word)
        //{
        //    strncat(res, text + (last - temp), word - last);
        //    if (strlen(word) <= N)
        //        strcat(res, word);
        //
        //    last = word + strlen(word);
        //    word = strtok(NULL, seps);
        //}
        //strcat(res, text + (last - temp));
 
        word = strtok(temp, seps);
        while (word)
        {
                        data = data + word;
                    if (strlen(data) > N)
                {
                  temp[N] = '\n';
                  temp[N + 1] = 0;
                }
                fputs(temp, target);
                        word = strtok(NULL, seps);
        }
        strcat(res, text + (last - temp));
    }
 
    fclose(source);
    fclose(target);
    free(text);
    free(temp);
}

Решение задачи: «Скопировать содержимое, ограничив длину строки N символами»

textual
Листинг программы
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
 
#define DEFAULT_OUTPUT_WIDTH (80)
#define PROGRAM_NAME argv[0]
#define INPUT_FILE_NAME argv[1]
#define OUTPUT_FILE_NAME argv[2]
#define OUTPUT_WIDTH argv[3]
#define INPUT_BUFFER_SIZE (2048)
 
int main(int argc, char ** argv) {
    FILE * fIn, * fOut;
    char * bufIn, * bufOut, * posPtr;
    size_t inpLen, outLen, tmpLen;
    
    if ( argc < 2 ) {
        fprintf(stderr, "USAGE: %s input_file [output_file [width]]\n", PROGRAM_NAME);
        exit(EXIT_FAILURE);
    }
    
    if ( argc == 4 ) {
        outLen = atoi(OUTPUT_WIDTH);
        if ( outLen < 1 || outLen >= INPUT_BUFFER_SIZE ) {
            fprintf(stderr, "%s: wrong parameter to output width - %lu\n", PROGRAM_NAME, outLen);
            exit(EXIT_FAILURE);
        }
    }
    else
        outLen = DEFAULT_OUTPUT_WIDTH;
    
    if ( ! ( bufIn = malloc(INPUT_BUFFER_SIZE) ) ) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    
    if ( ! ( bufOut = malloc(outLen + 2) ) ) {
        free(bufIn);
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    
    if ( ! ( fIn = fopen(INPUT_FILE_NAME, "r") ) ) {
        fprintf(stderr, "%s: can't open file %s for input!\n", PROGRAM_NAME, INPUT_FILE_NAME);
        free(bufIn);
        free(bufOut);
        exit(EXIT_FAILURE);
    }
    
    if ( argc == 2 )
        fOut = stdout;
    else {
        if ( ! ( fOut = fopen(OUTPUT_FILE_NAME, "w") ) ) {
            fprintf(stderr, "%s: can't open file %s for output!\n", PROGRAM_NAME, OUTPUT_FILE_NAME);
            fclose(fIn);
            free(bufIn);
            free(bufOut);
            exit(EXIT_FAILURE);
        }
    }
    
    while ( fgets(bufIn, INPUT_BUFFER_SIZE, fIn) ) {
        while ( ( inpLen = strlen(bufIn) ) > outLen ) {
            for ( posPtr = bufIn + outLen - 1; posPtr >= bufIn && ! isspace(*posPtr); --posPtr )
                ;
            if ( posPtr < bufIn ) {
                memcpy(bufOut, bufIn, outLen);
                bufOut[outLen] = '\n';
                bufOut[outLen + 1] = '\0';
                if ( fprintf(fOut, "%s", bufOut) == EOF ) {
                    fprintf(stderr, "%s: can't write to output file!\n", PROGRAM_NAME);
                    if ( fclose(fIn) )
                        perror("While close input file");
                    if ( fclose(fOut) )
                        perror("While close output file");
                    free(bufIn);
                    free(bufOut);
                    exit(EXIT_FAILURE);
                }
                memmove(bufIn, bufIn + outLen, strlen(bufIn + outLen) + 1);
            }
            else {
                tmpLen = posPtr - bufIn;
                memcpy(bufOut, bufIn, tmpLen);
                bufOut[tmpLen] = '\n';
                bufOut[tmpLen + 1] = '\0';
                if ( fprintf(fOut, "%s", bufOut) == EOF ) {
                    fprintf(stderr, "%s: can't write to output file!\n", PROGRAM_NAME);
                    if ( fclose(fIn) )
                        perror("While close input file");
                    if ( fclose(fOut) )
                        perror("While close output file");
                    free(bufIn);
                    free(bufOut);
                    exit(EXIT_FAILURE);
                }
                memmove(bufIn, bufIn + tmpLen + 1, strlen(bufIn + tmpLen));
            }
        }
        if ( inpLen ) {
            if ( fprintf(fOut, "%s", bufIn) == EOF ) {
                fprintf(stderr, "%s: can't write to output file!\n", PROGRAM_NAME);
                if ( fclose(fIn) )
                    perror("While close input file");
                if ( fclose(fOut) )
                    perror("While close output file");
                free(bufIn);
                free(bufOut);
                exit(EXIT_FAILURE);
            }
        }
    }
    
    if ( ferror(fIn) ) {
        fprintf(stderr, "%s: error while reading input file!\n", PROGRAM_NAME);
        if ( fclose(fIn) )
            perror("While close input file");
        if ( fclose(fOut) )
            perror("While close output file");
        free(bufIn);
        free(bufOut);
        exit(EXIT_FAILURE);
    }
    
    if ( fclose(fIn) )
        perror("While close input file");
    if ( fOut != stdout && fclose(fOut) )
        perror("While close output file");
    
    free(bufIn);
    free(bufOut);
    
    exit(EXIT_SUCCESS);
}

Объяснение кода листинга программы

Этот код предназначен для копирования содержимого из одного файла в другой с ограничением на количество символов в каждой строке. Он использует стандартные библиотеки C и может быть скомпилирован с помощью любого компилятора C. Список переменных и их значений:

  1. argc - количество аргументов в командной строке (обычно 2 или 4)
  2. argv - массив строк, содержащих параметры командной строки
  3. PROGRAM_NAME - имя программы (обычно имя исполняемого файла)
  4. INPUT_FILE_NAME - имя входного файла
  5. OUTPUT_FILE_NAME - имя выходного файла (если не указано, то это stdout)
  6. OUTPUT_WIDTH - ширина вывода (если не указано, то это 80)
  7. DEFAULT_OUTPUT_WIDTH - значение по умолчанию для OUTPUT_WIDTH, равное 80
  8. INPUT_BUFFER_SIZE - размер буфера ввода, равный 2048
  9. fIn - файловый указатель на входной файл
  10. fOut - файловый указатель на выходной файл (может быть stdout)
  11. bufIn - указатель на буфер ввода
  12. bufOut - указатель на буфер вывода
  13. inpLen - длина строки в буфере ввода
  14. outLen - длина строки в буфере вывода
  15. tmpLen - временная переменная для хранения длины строки
  16. posPtr - указатель на текущую позицию в строке
  17. isspace - функция, проверяющая, является ли символ пробелом
  18. fprintf - функция, используемая для записи в файл вывода
  19. fclose - функция, используемая для закрытия файла
  20. perror - функция, используемая для вывода сообщения об ошибке Основной цикл программы считывает строки из входного файла и записывает их в выходной файл, обрезая строки до заданной ширины. Если входной файл содержит символы новой строки ('\n'), они сохраняются в выходном файле. Если выходной файл не stdout, он закрывается после записи всех строк.

Оцени полезность:

8   голосов , оценка 4.25 из 5
Похожие ответы