公司动态

山东大学程序设计思维-记事本:从零实现一个支持粘滞选择与查找的文本编辑器

📅 2026/7/15 23:37:31
山东大学程序设计思维-记事本:从零实现一个支持粘滞选择与查找的文本编辑器
1. 项目需求分析实现一个支持粘滞选择和区域查找的文本编辑器核心功能包括多行文本存储与光标移动字符插入/删除/换行操作类似Shift方向键的连续选择粘滞功能在选中区域中查找字符串基础的字数统计功能数据结构选择使用vectorstring存储文本行是理想方案每行用字符串存储字符行号作为vector索引。相比链表结构vector支持随机访问更适合频繁的光标跳转操作。实测发现当处理5000行以上的文本时需要注意行合并时避免频繁内存重分配跨行操作时注意迭代器失效问题粘贴多行文本时预留足够容量2. 核心模块实现2.1 文本存储与光标系统vectorstring text_buffer; // 文本存储 int cursor_row 0; // 当前行(0-based) int cursor_col 0; // 当前列(0-based) void move_cursor(string cmd) { if(cmd Home) cursor_col 0; else if(cmd End) cursor_col text_buffer[cursor_row].size(); else if(cmd Up) { if(cursor_row 0) { cursor_row--; cursor_col min(cursor_col, (int)text_buffer[cursor_row].size()); } } // 其他移动命令... }避坑指南移动光标时要检查边界条件如第一行/最后一行跨行移动时注意目标行的长度限制列位置始终不能超过当前行长度2.2 粘滞选择功能struct Selection { int start_row, start_col; int end_row, end_col; bool active false; } current_selection; void toggle_sticky_mode() { if(!sticky_mode) { // 记录起始点 current_selection.start_row cursor_row; current_selection.start_col cursor_col; } else { // 检查是否形成有效选区 if(cursor_row ! start_row || cursor_col ! start_col) { current_selection.end_row cursor_row; current_selection.end_col cursor_col; current_selection.active true; } } sticky_mode !sticky_mode; }实现技巧使用标准化存储确保start位置end位置处理跨行选区时按行分段处理任何非移动操作如输入/删除都会取消选区3. 高级功能实现3.1 区域查找算法int count_occurrences(const string word, bool in_selection) { int count 0; if(in_selection) { // 只在选区内查找 for(int r sel.start_row; r sel.end_row; r) { string line text_buffer[r]; int start (r sel.start_row) ? sel.start_col : 0; int end (r sel.end_row) ? sel.end_col : line.size(); size_t pos line.find(word, start); while(pos ! string::npos pos end - word.size()) { count; pos line.find(word, pos 1); } } } else { // 全局查找 for(const auto line : text_buffer) { size_t pos line.find(word); while(pos ! string::npos) { count; pos line.find(word, pos 1); } } } return count; }优化点使用KMP算法提升长文本查找效率对空选区做特殊处理区分大小写查找可扩展3.2 字数统计实现int count_chars(bool in_selection) { int count 0; if(in_selection) { // 统计选区可见字符排除空格/换行 for(int r sel.start_row; r sel.end_row; r) { const string line text_buffer[r]; int start (r sel.start_row) ? sel.start_col : 0; int end (r sel.end_row) ? sel.end_col : line.size(); for(int i start; i end; i) { if(line[i] ! line[i] ! \n) count; } } } else { // 全局统计 for(const auto line : text_buffer) { for(char c : line) { if(c ! c ! \n) count; } } } return count; }4. 实战调试技巧常见问题排查循环提前终止检查循环条件边界值内存越界所有数组访问前检查size()选区计算错误标准化选区坐标确保startend调试案例 曾遇到粘贴多行文本时程序崩溃发现是vector迭代器失效问题。解决方案// 错误写法会导致迭代器失效 for(auto it text_buffer.begin(); it ! text_buffer.end(); it) { if(需要插入行) { text_buffer.insert(it, new_line); // 使it失效 } } // 正确写法 for(int i 0; i text_buffer.size(); ) { if(需要插入行) { text_buffer.insert(text_buffer.begin() i, new_line); i; // 跳过新插入的行 } i; }5. 扩展功能建议撤销/重做系统vectorEditorState history; void save_state() { history.push_back({text_buffer, cursor_pos}); if(history.size() 100) history.erase(history.begin()); }语法高亮使用正则表达式匹配关键词为不同token类型分配颜色多文件编辑使用多个vector 存储不同文件实现tab页切换逻辑这个项目让我深刻理解了文本编辑器的工作原理。最难的部分是处理各种边界条件比如跨行操作时的光标定位。建议在实现核心功能后先用小文本测试再逐步扩大测试规模。