Lesson28 PoEdu培训第三课 项目篇(2) 小说阅读器 章节分割部分
文章类别: 培训作业 0 评论

Lesson28 PoEdu培训第三课 项目篇(2) 小说阅读器 章节分割部分

文章类别: 培训作业 0 评论

老师未批改

小说阅读器的章节分割部分

程序源代码:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <string.h>        // 使用str系列的函数
#include <conio.h>        // 为了使用 _getch()
#include <direct.h>        // 为了使用 _mkdir
#include <errno.h>        // 为了查看错误状态和使用 strerror
#include <stdlib.h>        // 为了使用 strtod
#include <time.h>        // 计算用时

#define MAX_LEN 1024    // 最大数组长度
#define MID_LEN 512        // 中间的数组长度
#define MIN_LEN 255        // 最小的数组长度
#define SECTION_LEN 6    // 第 和 集 之间的最大间隔字符 也就是3个汉字
#define CHAPTER_LEN 10    // 第 和 章 之间的最大间隔字符 也就是5个汉字

// 退出状态码
typedef enum EXIT_CODE {
    NORMAL = 0,
    OPEN_FAILD = -1,
    SPLIT_FAILD = -2
} ExitCode;

char g_strBookName[MIN_LEN] = { 0 };    // 书名
char g_sectionDir[MIN_LEN] = { 0 };        // 每一集的路径
char g_chapterName[MID_LEN] = { 0 };    // 每一章的文件路径及名称
FILE* g_fChapterFile = NULL; // 章节文件
FILE* g_fDirectoryFile = NULL; // 目录文件

// 去掉字符串中的字符
int replaceCharToNull(char* strSource, char ch)
{
    int i = 0;
    for (; i < strlen(strSource); i++)
    {
        if ((*strSource + i) == ch)
        {
            *(strSource + i) = '\0';
            break;
        }
    }
    return i;
}


/**
* 去掉不能当文件名的字符
*
* 参数:
*    str 要建立的路径
*
* 返回值:
*    处理的字符个数
*/
int checkAndHandleName(char* str)
{
    int iRet = 0;

    for (int i = 0; i < strlen(str); i++)
    {
        char ch = *(str + i);
        switch (ch)
        {
        // case '\\':
        case '/':
        case '|':
        case '"':
        case '?':
        case ':':
        case '*':
        case '>':
        case '<':
            *(str + i) = '_';
            iRet++;
            break;
        case '\r':
        case '\n':
            *(str + i) = '\0';
            iRet++;
            break;
        default:
            break;
        }
    }
    return iRet;
}


/**
* 创建文件夹
*/
int createDir(char* str)
{
    int iRet = 0;
    checkAndHandleName(str);

    iRet = _mkdir(str);
    if (iRet < 0)
    {
        printf("创建文件夹[%s]失败!\n", str);
        perror(strerror(errno));
    }

    return iRet;
}

// 获取文件大小
long getFileSize(FILE* fp)
{
    long szBook = 0;
    fseek(fp, 0L, SEEK_END);
    szBook = ftell(fp);
    return szBook;
}

// 打开文本
int openBook(FILE** file, char* strBookName)
{
    int iRet = 0;

    *file = fopen(strBookName, "r+");
    if (*file == NULL)
    {
        perror(strerror(errno));
        iRet = -1;
    } 
    else
    {
        strncpy(g_strBookName, strBookName, strlen(strBookName) - 4);
        createDir(g_strBookName);
    }

    return iRet;
}

// 保存目录
int saveSection(char* strLine)
{
    int iRet = -1;

    if (!g_fDirectoryFile)
    {
        g_fDirectoryFile = fopen("目录.txt", "a+");
    }
    else
    {
        fputs(strLine, g_fDirectoryFile);
        iRet = 0;
    }
    return iRet;
}

/**
 * 检查分集
 * 
 * 参数:
 *    strLine : 要检查的字符串
 *
 * 返回值:
 *    0: 是分集并且完全正确运行完成
 *    <0: 运行出现错误
 */
int checkSection(char* strLine)
{
    int iRet = -1;

    char strSection[MIN_LEN] = { 0 };
    char* pFind1 = NULL;
    char* pFind2 = NULL;
    // 第一个字是 第
    if ((pFind1 = strstr(strLine, "第")) != NULL && pFind1 == strLine) {
        // 并且有 集, 并且2个字之间差的不大
        pFind2 = strstr(strLine, "集");
        int iFar = (pFind2 - pFind1);
        if (pFind2 != NULL && (iFar <= SECTION_LEN))
        {
            strncpy(strSection, pFind1, strlen(pFind1)); // 连带换行一起复制
            iRet = 0;
            // 保存目录文件
            iRet += saveSection(strSection);
            // 创建分集文件夹
            sprintf(g_sectionDir, "%s\\%s", g_strBookName, strSection);
            iRet += createDir(g_sectionDir);
        }
    }

    return iRet;
}

// 创建章节文件
int createChapterFile(char* strChapterName)
{
    int iRet = -1;
    char sPathNameTmp[MIN_LEN] = { 0 };
    char sPathName[MIN_LEN] = { 0 };
    sprintf(sPathNameTmp, "%s\\%s", g_sectionDir, strChapterName);
    checkAndHandleName(sPathNameTmp);
    sprintf(sPathName, "%s.txt", sPathNameTmp);
    if (g_fChapterFile) fclose(g_fChapterFile);
    g_fChapterFile = fopen(sPathName, "w");
    if (g_fChapterFile)
    {
        strncpy(g_chapterName, sPathName, MID_LEN);
        iRet = 0;
    }
    return iRet;
}


/**
 * 保存章节文件
 */
int saveChapterFile(char* strLine)
{
    int iRet = -1;
    
    if (!g_fChapterFile)
    {
        iRet = -2;
    }
    else
    {
        fputs(strLine, g_fChapterFile);
        iRet = 0;
    }
    return iRet;
}

/**
* 检查章节名
*
* 参数:
*    strLine : 要检查的字符串
*
* 返回值:
*    0: 是章节名并且完全正确运行完成
*    <0: 运行出现错误
*/
int checkChapter(char* strLine)
{
    int iRet = -1;

    char strChapter[MIN_LEN] = { 0 };
    char* pFind1 = NULL;
    char* pFind2 = NULL;
    // 第一个字是 第
    if ((pFind1 = strstr(strLine, "第")) != NULL && pFind1 == strLine) {
        // 并且有 章, 并且2个字之间差的不大
        pFind2 = strstr(strLine, "章");
        
        if (pFind2 != NULL && ((pFind2 - pFind1) <= CHAPTER_LEN))
        {
            strncpy(strChapter, pFind1, strlen(pFind1)); // 连带换行一起复制
            iRet = 0;
            // 创建章节文件
            iRet += createChapterFile(strChapter);
            // 保存章节标题
            iRet += saveChapterFile(strLine);
            // 保存目录
            iRet += saveSection(strLine);
        }
    }

    return iRet;
}


/**
 * 分析一行数据
 */
int analyzeLine(char* strLine)
{
    int iRet = 0;

    // 跳过本行前边的空格 不进行匹配 
    int iIdx = 0;
    for (; iIdx < MAX_LEN; iIdx++)
    {
        if (*(strLine + iIdx) != ' ')
        {
            break;
        }
    }

    // 是不是 第*集, 是的话在checkSection中保存 不是 在进行下一步判断
    if (0 > checkSection(strLine + iIdx))
    {
        // 判断是不是  第*章, 是的话在checkChapter中保存
        if (0 > checkChapter(strLine + iIdx))
        {
            // 正文
            saveChapterFile(strLine);
        }
    }

    return iRet;
}

/**
 * 分割文件
 */
int splitBook(FILE* file, char* strFileName)
{
    int iRet = 0;

    char strLine[MAX_LEN] = { 0 };

    printf("开始处理....\n");
    clock_t start = clock();    

    fseek(file, 0L, SEEK_SET);

    while (fgets(strLine, MAX_LEN, file) != NULL)
    {
        analyzeLine(strLine);
        memset(strLine, 0x00, sizeof(strLine));
    }
    releaseAndClear();
    clock_t finish = clock();
    printf("\n处理完成, 耗时[%.3lf]秒.\n", ((double)finish-start)/1000);

    return iRet;
}

// 清理工作
int releaseAndClear()
{
    int iRet = 0;
    if (g_fChapterFile) fclose(g_fChapterFile);
    if (g_fDirectoryFile) fclose(g_fDirectoryFile);
    return iRet;
}

int main()
{
    int iExitCode = NORMAL;

    printf("请输入小说名称:\n");
    char strBookName[MIN_LEN] = { 0 };
    scanf_s("%s", strBookName, MIN_LEN);
    printf("[%s]\n", strBookName);

    FILE* fBook = NULL;

    if (0 != openBook(&fBook, strBookName))
    {
        printf("打开文件失败!程序退出....\n");
        iExitCode = OPEN_FAILD;

    } else     if (0 != splitBook(fBook, strBookName))
    {
        printf("分析小说章节目录失败!程序退出....\n");
        iExitCode = SPLIT_FAILD;
    }

    printf("请按任意键退出.....");
    _getch();
    if (fBook != NULL)
    {
        fclose(fBook);
    }

    return iExitCode;
}

运行效果:
Alt 运行效果

注: 电脑性能决定了时间, 演示效果中的时间不是每次都相同, 不同电脑的时间会有所差异.

如有错误,请提出指正!谢谢.

回复