当前位置: 首页 > news >正文

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

1. 项目需求分析

实现一个支持粘滞选择和区域查找的文本编辑器,核心功能包括:

  • 多行文本存储与光标移动
  • 字符插入/删除/换行操作
  • 类似Shift+方向键的连续选择(粘滞功能)
  • 在选中区域中查找字符串
  • 基础的字数统计功能

数据结构选择:使用vector<string>存储文本行是理想方案,每行用字符串存储字符,行号作为vector索引。相比链表结构,vector支持随机访问,更适合频繁的光标跳转操作。

实测发现,当处理5000行以上的文本时,需要注意:

  1. 行合并时避免频繁内存重分配
  2. 跨行操作时注意迭代器失效问题
  3. 粘贴多行文本时预留足够容量

2. 核心模块实现

2.1 文本存储与光标系统

vector<string> 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; }

实现技巧

  1. 使用标准化存储(确保start位置<=end位置)
  2. 处理跨行选区时按行分段处理
  3. 任何非移动操作(如输入/删除)都会取消选区

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. 实战调试技巧

常见问题排查

  1. 循环提前终止:检查循环条件边界值
  2. 内存越界:所有数组访问前检查size()
  3. 选区计算错误:标准化选区坐标(确保start<=end)

调试案例: 曾遇到粘贴多行文本时程序崩溃,发现是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. 扩展功能建议

  1. 撤销/重做系统
vector<EditorState> history; void save_state() { history.push_back({text_buffer, cursor_pos}); if(history.size() > 100) history.erase(history.begin()); }
  1. 语法高亮
  • 使用正则表达式匹配关键词
  • 为不同token类型分配颜色
  1. 多文件编辑
  • 使用多个vector 存储不同文件
  • 实现tab页切换逻辑

这个项目让我深刻理解了文本编辑器的工作原理。最难的部分是处理各种边界条件,比如跨行操作时的光标定位。建议在实现核心功能后,先用小文本测试,再逐步扩大测试规模。

http://www.jsqmd.com/news/1196766/

相关文章:

  • 宇舶中国官方售后服务中心|服务热线及全部维修地址权威信息公示(2026年7月最新) - 亨得利官方服务中心
  • 道心通明:一个觉醒者的宇宙观
  • 【C/C++ 实用工具】从原理到实战:主流内存检测工具深度剖析
  • 基于STM32单片机的智能全自动洗衣机蓝牙/WiFi APP设计DIY-T157
  • 恶意代码沙箱检测架构:在隔离环境里放毒看反应
  • 量化实盘异常处理流程:断线、部分成交、重复委托与人工接管
  • 热电效应三兄弟:从赛贝克到帕尔帖,揭秘半导体制冷片背后的物理世界
  • 基于STC89C52与DHT11的智能家居环境调控系统设计与实现
  • 心跳监控有什么用?云哨兵有一台“任务打卡机”
  • 【C语言】深入探究字母大小写转换的三种底层逻辑
  • STM32平衡小车进阶调试(调参篇)
  • 模板驱动型文档自动化:零代码实现动态内容填充与品牌一致性
  • 混沌初开:模糊算法与生命智能
  • 零代码量化软件试用验收:用一条低频规则检查回测与提醒
  • TFLite 异步推理流水线架构:用 C++ future/promise 榨干边缘 SoC 的每一毫秒计算力
  • 打卡第32天 - P1918 - 2026 - 7 - 15
  • 2026美妆护肤SEO/GEO服务商对比:从“被搜索”到“被推荐”,谁真正懂行? - GEO优化
  • 计算机软件工程毕业设计开题报告撰写全流程与避坑指南
  • Vite 生产部署的性能基线与持续回归检测方案
  • 配送--案例
  • 打破企业数据语义鸿沟:本体语义平台实战方法论
  • Agent 搜索栈正在替代 RAG
  • NCNN 多线程推理的负载均衡调度对决:按输出通道均分与按计算量均分两种策略的基准测试报告
  • 嵌入式接口时序设计:从建立时间到PCB布局的实战指南
  • 芝柏中国官方售后服务中心|地址与售后服务电话权威信息通知(2026年7月更新) - 亨得利钟表维修中心
  • 【进阶运营指南】CSDN原力等级:解锁社区影响力与创作权益的实战攻略
  • C++编程思想深度解析:从RAII到模板,构建系统级编程能力
  • C++实战-跨平台构建中静态库与动态库的配置与选择策略
  • C++实现文本转语音引擎:从架构设计到工程实践
  • 2026 年当下,靠谱的G657A2光纤公司怎么联系,揭秘:这个光纤如何让你网络速度飙升十倍? - 行业严选官