文本编辑原理

由于我总是对现有的编辑不满意,我一直想开始的一个项目就是我自己的文本编辑器。 不过,做文本编辑是很重要的事情。

除了分析现有文本编辑器的源代码之外,有没有关于这个主题的任何书籍或其他资源(如学术工作)? 我特别感兴趣的东西,教如何处理内存和如何pipe理文本插入(如果你有一个100 MB的文件,并希望在X位置添加一个字符,你不能只是巨大的文本块memmove … )。

看看Rob Pike对他的Sam文本编辑器的描述。 一定要浏览高级概览和命令语言。 他在本文后面描述了parsing,内存pipe理和数据结构。

另外,请看Russ Cox 简单的正则expression式实现 。 这很容易遵循,并可能打开现有的正则expression式库之外的一些门。

多年来我写了不less文本编辑。 当然,最简单的方法是pipe理一个长长的字符序列,在其中复制所有内容以插入任何字符。 我用过的其他技术包括:

  • 将文本文件表示为文本行的双向链接列表。
  • 构build一个树状数据结构(有时称为“绳索” ),它以一串固定的字符开始,但能够分割,插入和删除文本块,而不必移动文本的所有其余部分。

许多旧的Borland示例书籍都使用了文本编辑器作为教程示例。 您偶尔可以在使用过的书店中几乎免费地find这些副本。

这里有一个很好的教程,在更现代的背景下涵盖了很多相关的主题:

  • 一个Win32文本编辑器的devise和实现

这个问题的其他答案覆盖了间隙缓冲区。

另一个现代的报道是AvalonEdit的描述

并从以下额外的细节:

书中还有大量的细节/内容(关于SharpDevelop):

推荐应要求回答:

Kernighan和Plaugher的古董“ Pascal软件工具 ”以一种既没有真正的string也没有指针的语言来实现ed编辑器。 它包含了对任何文本编辑器的基础devise考虑的很好的概述。

Craig Finseth基于他的硕士论文的文本编辑工艺涵盖了这些主题。 它在networking上是免费的。 OTOH很老了,并没有提到一些想法,比如在以前的小型计算机上不太实用的绳索。

一个仍然有效的旧方法叫做间隙缓冲器。 其基本思想是将文本放入缓冲区,而不是将所有文本放在一个块中,而是在光标处创build一个“间隙”,将所有位于光标之前的文本放在缓冲区的开始处,光标位于缓冲区末尾的文本。 大多数插入操作都是在光标处进行的,您可以在不移动任何东西的情况下进行插入(直到或者除非您将缓冲区溢出)。 当用户移动光标时,将合适的文本从分割的一边移到另一边。

给定典型的控件(光标向左,向右,向上,向下,向上翻页,向下翻页),您通常处理的最大移动量是一次一页,这通常比键盘重复要快得多。 当然,如果你有一个真正的巨大的文件和一个“goto line”命令,或者按照这个顺序,它可以放慢一点。 如果你打算做很多这样的事情,毫无疑问有更好的结构来使用…

本文比较了许多可用于文本编辑器的数据结构,包括这里已经提到的一些数据结构(例如间隙缓冲区)以及其他几个(例如块表)。 这篇文章虽然陈旧,但是我认为它仍然涵盖了所有主要的select,并且在性能,复杂性和空间开销方面做了很好的比较。

我知道堆栈溢出的答案不只是应该是链接,但这仍然是我所发现的所需信息的最佳信息来源,并且在这里回答总结太长了。 如果链接过时,请search新墨西哥大学的Charles Crowley的“ 文本序列的数据结构 ”。

Scintilla组件使用拆分缓冲区,沿着在Scintilla和SciTE Related Sites页面链接的文本中解释的理论。
链接的页面是位图文本编辑器中的数据结构 。
即使有兆字节的文件,分割缓冲区也certificate了它的效果。 使用二级结构(例如,一个行开始列表)也可以帮助。

下面是Microsoft的“专业人员”如何做到的:

MS Word使用片段数据结构。 字符位置的递增数组与大数组结构保持并行,该大数组结构包含指向原始文件(文本加载的文本)或新添加字符的仅附加缓冲区的指针。

Windows中随处可见的编辑控件根本不使用数据结构。 记事本只是使用多行EDIT控件。 用堆查看器检查它。 编辑控件只维护换行符和制表位的缓冲区。

如果你打算在Windows中创build一个简单的非格式文本编辑器,你可以很容易地inheritanceEDIT控件来添加特性。

如何pipe理文本插入(如果你有一个100 MB的文件,并希望在x位置添加一个字符,你不能只是memove巨大的文本块…)。

使文本文件成为一个链接列表,其中每一行都是一个条目。

那么如果你知道一般人们的插入点会比较less的话,你可以在你的原始文本缓冲区中保存一个指针数组,当用户试图插入它的时候,你可以通过产生另一个指针指向其余的指针创build第一个指针的长度,使其停止在插入点处,并为要插入的文本添加第三个指针,有点像:

 long original text la la la ^ *^ | 2nd part 1st part 

星星指向一个新的文本缓冲区,开始添加要插入的文本。

当你渲染(或者通常parsing)你的文本文件时,你循环指针数组,然后在每个缓冲区上执行你的工作。 当然,如果缓冲区足够小,可以跳过添加一个新的缓冲区部分,但这只是启发式的方法,尝试每个缓冲区部分,并获得最佳效果。

你也可以考虑把加载的文本文件分成多个缓冲区,每隔1MB左右,因为如果你将文件加载到一个缓冲区中,你将需要为插入的文本创build一个新的缓冲区,因为它的大小。 再次,这是一个启发式优化。