使用C#逐页读取RTF文档并提取带对应页码的指定内容
嘿,我帮你搞定这个RTF逐页提取关键词和页码的问题!之前用RichTextBox只能拿到全量文本确实头疼,因为RTF本身并没有原生存储页码信息——页码是渲染时根据排版计算出来的。不过我们可以借助WinForms的打印机制来绕开这个问题,具体思路和代码如下:
核心思路
利用Windows Forms的PrintDocument控件结合RichTextBox的打印能力:当触发打印流程时,PrintDocument会逐页触发PrintPage事件,我们可以在这个事件里获取当前页的文本内容,同时记录对应的页码,最后在每页文本中搜索目标关键词并建立映射。
具体实现步骤
- 在VS2015的WinForms项目中,添加
RichTextBox、PrintDocument和PrintPreviewDialog控件(也可以通过代码动态创建)。 - 将RTF文件加载到
RichTextBox中。 - 绑定
PrintDocument的PrintPage事件,在事件处理逻辑中提取当前页文本、搜索关键词并记录页码。 - 通过
PrintPreviewDialog触发打印流程(不需要实际打印,只是用来触发分页事件)。
完整代码示例
首先在Form类中声明必要的变量:
using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; namespace RTFFilePageReader { public partial class MainForm : Form { // 存储关键词和对应页码的映射 private Dictionary<string, List<int>> _keywordPageMap = new Dictionary<string, List<int>>(); // 当前页码计数器 private int _currentPage = 0; // 你要搜索的目标关键词列表 private List<string> _targetKeywords = new List<string> { "特定词语1", "特定词语2" }; public MainForm() { InitializeComponent(); }
然后添加加载RTF和触发分页处理的方法:
private void btnProcess_Click(object sender, EventArgs e) { // 重置状态 _keywordPageMap.Clear(); _currentPage = 0; // 加载RTF文件到RichTextBox try { richTextBox1.LoadFile("你的RTF文件路径.rtf", RichTextBoxStreamType.RichText); } catch (Exception ex) { MessageBox.Show($"加载文件失败: {ex.Message}"); return; } // 配置PrintDocument printDocument1.DefaultPageSettings.Margins = new System.Drawing.Printing.Margins(50, 50, 50, 50); printDocument1.PrintPage += PrintDocument1_PrintPage; // 用PrintPreviewDialog触发分页事件(最小化窗口避免干扰) using (PrintPreviewDialog previewDialog = new PrintPreviewDialog()) { previewDialog.Document = printDocument1; previewDialog.WindowState = FormWindowState.Minimized; previewDialog.ShowDialog(); } // 输出结果到控制台或者界面 ShowKeywordResults(); }
接下来是核心的PrintPage事件处理逻辑:
private void PrintDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { _currentPage++; // 获取当前页文本的起始和结束索引 int startCharIndex = richTextBox1.GetCharIndexFromPosition(new Point(0, e.MarginBounds.Top)); int endCharIndex = richTextBox1.GetCharIndexFromPosition(new Point(0, e.MarginBounds.Bottom)); // 处理最后一页的边界情况 if (endCharIndex > richTextBox1.Text.Length - 1) endCharIndex = richTextBox1.Text.Length - 1; // 提取当前页的文本 string currentPageText = richTextBox1.Text.Substring(startCharIndex, endCharIndex - startCharIndex + 1); // 在当前页文本中搜索目标关键词 foreach (string keyword in _targetKeywords) { int keywordIndex = currentPageText.IndexOf(keyword, StringComparison.OrdinalIgnoreCase); while (keywordIndex != -1) { // 如果关键词不在映射中,初始化列表 if (!_keywordPageMap.ContainsKey(keyword)) _keywordPageMap[keyword] = new List<int>(); // 避免重复记录同一页码 if (!_keywordPageMap[keyword].Contains(_currentPage)) _keywordPageMap[keyword].Add(_currentPage); // 继续搜索下一个匹配项 keywordIndex = currentPageText.IndexOf(keyword, keywordIndex + keyword.Length, StringComparison.OrdinalIgnoreCase); } } // 告诉PrintDocument是否还有下一页 e.HasMorePages = endCharIndex < richTextBox1.Text.Length - 1; }
最后添加结果展示的方法:
private void ShowKeywordResults() { string result = ""; foreach (var kvp in _keywordPageMap) { result += $"关键词: *{kvp.Key}*,出现页码: {string.Join(", ", kvp.Value)}\n"; } MessageBox.Show(result, "关键词搜索结果"); // 也可以输出到控制台 Console.WriteLine(result); } } }
注意事项
- 分页一致性:
PrintDocument的页面设置(纸张大小、边距)会直接影响分页结果,要确保和你实际文档的排版设置一致,否则页码可能不准确。 - 复杂格式处理:如果RTF包含表格、图片等复杂元素,可能需要调整
GetCharIndexFromPosition的坐标计算,确保能准确获取每页的文本范围。 - 性能优化:如果是超大文档,可以考虑异步处理,避免UI卡顿。
内容的提问来源于stack exchange,提问作者Anish Sivadas
相关产品推荐
相关产品推荐

