#include <stdio.h>
// 引入标准输入输出库
#include <stdlib.h>
// 引入标准库函数
#include <string.h>
// 引入字符串处理库函数

#define MAX_SIZE 100
// 定义每个结点可以存储的最大字符数
#define PAGE_SIZE 10
// 定义每页显示的字符数

// 定义结点结构体,存储小说内容和指针指向前后结点
typedef struct Node {
    char content[MAX_SIZE];
    // 存储结点的内容,最大长度为 MAX_SIZE
    struct Node* next;
    // 指向下一个结点
    struct Node* prev;
    // 指向前一个结点
} Node;

// 定义小说编辑器结构体,存储头结点、当前结点和结点总数
typedef struct {
    Node* head;
    // 指向链表的头结点
    Node* current;
    // 指向当前正在操作的结点
    int totalNodes;
    // 链表中结点的总数
} NovelEditor;

// 定义用户结构体,存储用户名、密码和是否是作者
typedef struct {
    char username[20];
    // 存储用户名,最大长度为 20
    char password[20];
    // 存储密码,最大长度为 20
    int is_author;
    // 标识用户是否是作者,1 表示作者,0 表示读者
} User;

// 初始化小说编辑器
void init(NovelEditor* editor) {
    editor->head = NULL; // 初始化头结点为 NULL
    editor->current = NULL; // 初始化当前结点为 NULL
    editor->totalNodes = 0; // 初始化结点总数为 0
}

// 定位到指定的段号和段内偏移
void locate(NovelEditor* editor, int segment, int offset) {
    Node* curr = editor->head; // 从头结点开始遍历链表
    while (curr != NULL && segment > 1) { // 定位到指定段号
        curr = curr->next;
        segment--;
    }
    
    if (curr != NULL && offset <= MAX_SIZE) { // 检查段内偏移是否有效
        editor->current = curr; // 更新当前结点
        printf('定位成功到段号 %d,段内偏移 %d\n', segment, offset);
    }
    else {
        printf('定位失败\n');
    }
}

// 在当前结点插入字符串
void insertString(NovelEditor* editor, char* str) {
    if (editor->current == NULL) {
        printf('请先定位到位置再插入字符串\n');
        return;
    }
    
    int i = 0;
    Node* newNode = (Node*)malloc(sizeof(Node)); // 创建新结点
    while (str[i] != '\0' && editor->current->content[i] != '\0' && i < MAX_SIZE) { // 拷贝字符串到当前结点
        editor->current->content[i] = str[i];
        i++;
    }
    editor->current->content[i] = '\0'; // 在字符串末尾添加结束符 '\0'
    
    if (str[i] != '\0') { // 存在剩余未插入的字符串
        newNode->content[0] = '\0'; // 初始化新结点的内容为空字符串
        newNode->next = editor->current->next; // 将新结点链接到当前结点的后面
        newNode->prev = editor->current;
        editor->current->next = newNode;
        if (newNode->next != NULL) {
            newNode->next->prev = newNode;
        }
        editor->current = newNode;
        editor->totalNodes++;
        
        i++;
        while (str[i] != '\0' && i < MAX_SIZE) { // 拷贝剩余字符串到新结点
            editor->current->content[i - MAX_SIZE] = str[i];
            i++;
        }
        editor->current->content[i - MAX_SIZE] = '\0'; // 在字符串末尾添加结束符 '\0'
    }
    
    printf('字符串插入成功\n');
}

// 删除当前结点指定长度的字符串
void deleteString(NovelEditor* editor, int length) {
    if (editor->current == NULL) {
        printf('请先定位到位置再删除字符串\n');
        return;
    }
    
    int i = 0;
    while (editor->current->content[i] != '\0' && i < length && i < MAX_SIZE) { // 删除指定长度的字符串
        editor->current->content[i] = '\0';
        i++;
    }
    
    if (editor->current->content[i] == '\0') { // 当前结点已删除完毕
        Node* nextNode = editor->current->next;
        if (nextNode != NULL && nextNode->content[0] != '\0') { // 合并下一个结点
            while (i - MAX_SIZE < MAX_SIZE && nextNode->content[i - MAX_SIZE] != '\0') {
                editor->current->content[i - MAX_SIZE] = nextNode->content[i - MAX_SIZE];
                nextNode->content[i - MAX_SIZE] = '\0';
                i++;
            }
        }
        else { // 删除下一个结点
            editor->current->next = nextNode->next;
            if (nextNode->next != NULL) {
                nextNode->next->prev = editor->current;
            }
            free(nextNode);
            editor->totalNodes--;
        }
    }
    
    printf('字符串删除成功\n');
}

// 显示小说内容
void displayNovel(NovelEditor* editor) {
    Node* curr = editor->head; // 从头结点开始遍历链表
    int segment = 1; // 段号
    
    while (curr != NULL) { // 遍历输出链表中的内容
        printf('段号 %d: %s\n', segment, curr->content);
        curr = curr->next;
        segment++;
    }
}

// 显示当前结点之前指定长度的字符内容
void displayPage(NovelEditor* editor, int m) {
    if (editor->current == NULL) {
        printf('请先定位到位置再显示页面\n');
        return;
    }
    
    Node* curr = editor->current;
    int count = 0; // 统计字符数
    
    printf('当前位置前 %d 个字符内容为一页:\n', m);
    while (curr != NULL && count < m) { // 输出 m 个字符
        printf('%s', curr->content);
        count++;
        curr = curr->next;
    }
    printf('\n');
}

// 在小说中查找指定字符串并输出出现位置
void searchString(NovelEditor* editor, char* searchString) {
    Node* curr = editor->head; // 从头结点开始遍历链表
    int segment = 1; // 段号
    int offset = 0; // 段内偏移
    int count = 0; // 字串出现次数
    
    while (curr != NULL) { // 遍历链表中的每个结点
        char* ptr = curr->content;
        
        while ((ptr = strstr(ptr, searchString)) != NULL) { // 在结点内容中查找字串
            count++;
            printf('字串 '%s' 在文章中的坐标为 (段序号: %d, 段内偏移: %d)\n', searchString, segment, offset + (int)(ptr - curr->content));
            ptr += strlen(searchString);
        }
        
        curr = curr->next;
        segment++;
        offset += MAX_SIZE;
    }
    
    printf('字串 '%s' 在文章中的出现次数为 %d\n', searchString, count);
}

// 替换小说中指定字符串
void replaceString(NovelEditor* editor, char* searchString, char* replacement) {
    Node* curr = editor->head; // 从头结点开始遍历链表
    int segment = 1; // 段号
    int offset = 0; // 段内偏移
    int count = 0; // 字串出现次数
    
    while (curr != NULL) { // 遍历链表中的每个结点
        char* ptr = curr->content;
        
        while ((ptr = strstr(ptr, searchString)) != NULL) { // 在结点内容中查找字串
            count++;
            int searchLength = strlen(searchString);
            int replaceLength = strlen(replacement);
            int shift = replaceLength - searchLength;
            
            if (shift != 0) { // 需要插入或删除结点以适应替换后的字符串
                Node* newNode = (Node*)malloc(sizeof(Node));
                newNode->next = curr->next;
                newNode->prev = curr;
                curr->next = newNode;
                if (newNode->next != NULL) {
                    newNode->next->prev = newNode;
                }
                editor->totalNodes++;
                
                char* temp = ptr + searchLength;
                while (*temp != '\0') { // 将后续字符串拷贝到新结点
                    newNode->content[temp - ptr - searchLength] = *temp;
                    *temp = '\0';
                    temp++;
                }
                newNode->content[temp - ptr - searchLength] = '\0';
            }
            
            strncpy(ptr, replacement, replaceLength); // 将替换字符串拷贝到结点中
            ptr += replaceLength;
        }
        
        curr = curr->next;
        segment++;
        offset += MAX_SIZE;
    }
    
    printf('字串替换成功\n');
}

// 保存小说内容到文件
void saveNovel(NovelEditor* editor) {
    FILE* file = fopen('novel.txt', 'w'); // 打开名为'novel.txt'的文件以写入模式

    if (file == NULL) {
        printf('无法保存文件\n');
        return;
    }

    Node* curr = editor->head; // 从头结点开始遍历链表
    while (curr != NULL) { // 将链表中的内容写入文件
        fprintf(file, '%s', curr->content); // 写入内容到文件
        curr = curr->next;
    }

    fclose(file); // 关闭文件

    printf('小说保存成功\n');
}

// 从文件读取小说内容
void readNovel(NovelEditor* editor) {
    FILE* file = fopen('novel.txt', 'r'); // 打开名为'novel.txt'的文件以读取模式

    if (file == NULL) {
        printf('无法读取文件\n');
        return;
    }

    char content[MAX_SIZE];
    Node* prev = NULL;

    while (fgets(content, MAX_SIZE, file) != NULL) { // 从文件中逐行读取内容
        Node* newNode = (Node*)malloc(sizeof(Node));
        strncpy(newNode->content, content, MAX_SIZE); // 使用strncpy复制内容
        newNode->next = NULL;
        newNode->prev = prev;

        if (prev == NULL) {
            editor->head = newNode;
        }
        else {
            prev->next = newNode;
        }

        prev = newNode;
        editor->totalNodes++;
    }

    fclose(file); // 关闭文件

    printf('小说读取成功\n');
}

// 统计小说中单词、数字和标点符号数量
void countCharacters(NovelEditor* editor) {
    Node* curr = editor->head; // 从头结点开始遍历链表
    int wordCount = 0; // 单词数量
    int numberCount = 0; // 数字数量
    int punctuationCount = 0; // 标点符号数量

    while (curr != NULL) { // 遍历链表中的每个结点
        for (int i = 0; curr->content[i] != '\0'; i++) { // 遍历结点内容的每个字符
            if ((curr->content[i] >= 'A' && curr->content[i] <= 'Z') || (curr->content[i] >= 'a' && curr->content[i] <= 'z')) {
                wordCount++; // 字符为字母,增加单词数量
            }
            else if (curr->content[i] >= '0' && curr->content[i] <= '9') {
                numberCount++; // 字符为数字,增加数字数量
            }
            else if (curr->content[i] == '.' || curr->content[i] == ',' || curr->content[i] == ':' || curr->content[i] == ';' || curr->content[i] == '!' || curr->content[i] == '?') {
                punctuationCount++; // 字符为标点符号,增加标点符号数量
            }
        }

        curr = curr->next; // 移动到下一个结点
    }

    printf('单词数量: %d\n', wordCount);
    printf('数字数量: %d\n', numberCount);
    printf('标点符号数量: %d\n', punctuationCount);
}

// 删除指定段落的结点
void deleteParagraph(NovelEditor* editor, int segment) {
    Node* curr = editor->head; // 从头结点开始遍历链表
    int currSegment = 1; // 当前段号
    
    while (curr != NULL && currSegment < segment) { // 定位到指定的段落
        curr = curr->next;
        currSegment++;
    }
    
    if (curr != NULL) {
        if (curr->prev == NULL) { // 删除第一个结点
            editor->head = curr->next;
            if (curr->next != NULL) {
                curr->next->prev = NULL;
            }
        }
        else { // 删除中间或末尾结点
            curr->prev->next = curr->next;
            if (curr->next != NULL) {
                curr->next->prev = curr->prev;
            }
        }
        
        free(curr); // 释放内存
        editor->totalNodes--;
        
        printf('段落删除成功\n');
    }
    else {
        printf('没有找到指定的段落\n');
    }
}

// 复制当前结点的内容
void copyParagraph(NovelEditor* editor) {
    if (editor->current == NULL) {
        printf('请先定位到段落再复制\n');
        return;
    }
    
    Node* newNode = (Node*)malloc(sizeof(Node));
    strcpy(newNode->content, editor->current->content);
    newNode->next = editor->current->next;
    newNode->prev = editor->current;
    
    if (newNode->next != NULL) {
        newNode->next->prev = newNode;
    }
    
    editor->current->next = newNode;
    
    editor->totalNodes++;
    
    printf('段落复制成功\n');
}

// 用户登录函数
User* login() {
    User* user = (User*)malloc(sizeof(User));
    
    printf('请输入用户名: ');
    scanf('%s', user->username);
    
    printf('请输入密码: ');
    scanf('%s', user->password);
    
    printf('请选择用户类型(1-作者, 0-读者): ');
    scanf('%d', &(user->is_author));
    
    return user;
}

// 主函数
int main() {
    NovelEditor editor;
    init(&editor);
    
    User* user = login();
    if (user->is_author) {
        printf('作者登录成功\n');
    }
    else {
        printf('读者登录成功\n');
    }
    
    int choice;
    
    do {
        printf('\n小说编辑器系统主菜单\n');
        printf('1. 定位功能\n');
        printf('2. 字符串插入功能\n');
        printf('3. 字符串删除功能\n');
        printf('4. 小说显示功能\n');
        printf('5. 翻页显示功能\n');
        printf('6. 字符串查找和替换功能\n');
        printf('7. 小说保存功能\n');
        printf('8. 小说读取功能\n');
        printf('9. 统计功能\n');
        printf('10. 段落删除功能\n');
        printf('11. 段落复制功能\n');
        printf('0. 退出\n');
        printf('请选择操作: ');
        scanf('%d', &choice);
        
        switch (choice) {
            case 1: {
                int segment, offset;
                printf('输入段号和段内偏移: ');
                scanf('%d %d', &segment, &offset);
                locate(&editor, segment, offset);
                break;
            }
            case 2: {
                char insertString[MAX_SIZE];
                printf('输入要插入的字符串: ');
                scanf('%s', insertString);
                insertString(&editor, insertString);
                break;
            }
            case 3: {
                int length;
                printf('输入要删除的字符串长度: ');
                scanf('%d', &length);
                deleteString(&editor, length);
                break;
            }
            case 4:
                displayNovel(&editor);
                break;
            case 5: {
                int m;
                printf('输入每页字符数 m: ');
                scanf('%d', &m);
                displayPage(&editor, m);
                break;
            }
            case 6: {
                char searchString[MAX_SIZE], replaceString[MAX_SIZE];
                printf('输入要查找的字符串: ');
                scanf('%s', searchString);
                printf('输入要替换的字符串: ');
                scanf('%s', replaceString);
                searchString(&editor, searchString);
                replaceString(&editor, searchString, replaceString);
                break;
            }
            case 7:
                saveNovel(&editor);
                break;
            case 8:
                readNovel(&editor);
                break;
            case 9:
                countCharacters(&editor);
                break;
            case 10: {
                int segment;
                printf('输入要删除的段落号: ');
                scanf('%d', &segment);
                deleteParagraph(&editor, segment);
                break;
            }
            case 11:
                copyParagraph(&editor);
                break;
            case 0:
                printf('退出小说编辑器系统\n');
                break;
            default:
                printf('无效的选择\n');
                break;
        }
    } while (choice != 0);
    
    return 0;
}

这段代码实现了一个简单的小说编辑器系统,包括登录、定位、字符串插入、字符串删除、小说显示、翻页显示、字符串查找和替换、小说保存、小说读取、统计、段落删除和段落复制等功能。

希望以上代码能够满足你的需求。如果有任何疑问,请随时提问。

C 语言实现小说编辑器:代码注释详解

原文地址: https://www.cveoy.top/t/topic/bcSX 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录