编辑文本缓冲区[关闭]

Posted

技术标签:

【中文标题】编辑文本缓冲区[关闭]【英文标题】:Editing a text buffer [closed] 【发布时间】:2008-09-30 18:06:54 【问题描述】:

好的,这是一个有点厚颜无耻的问题。我想构建一个简单的文本编辑器(使用我自己的文本模式屏幕处​​理)。我只想要一个可用于表示文本缓冲区的数据结构的好示例,以及一些简单的字符/文本插入/删除示例。我可以自己处理所有其余的代码(文件 i/o、控制台 i/o 等)。一个不错的简单编辑器源的链接会很棒(C 或 C++)。

【问题讨论】:

【参考方案1】:

我曾经在一家主要产品是文本编辑器的公司工作。虽然我主要研究它的脚本语言,但编辑器本身的内部设计自然是讨论的主要话题。

似乎它分解成两个一般的思路。一种是您自己存储每一行​​,然后将它们链接到一个链表或其他您满意的整体数据结构中。优点是任何面向行的编辑操作(例如删除整行,或在文件中移动行块)都非常容易实现,因此速度极快。不利的一面是加载和保存文件需要更多的工作,因为您必须遍历整个文件并构建这些数据结构。

当时的另一种思路是在未更改的情况下尝试将大块文本保持在一起,而不考虑换行符,仅在编辑需要时将它们分解。优点是可以很容易地将未经编辑的文件大块分解为文件。加载文件、更改一行和保存文件的简单编辑速度非常快。缺点是执行面向行或列块的操作非常耗时,因为您必须解析这些文本块并移动大量数据。

我们始终坚持以线为导向的设计,无论其价值如何,我们的产品被认为是当时最快的编辑器之一。

【讨论】:

【参考方案2】:

“四人帮”一书 (Design Patterns) 有一个基于 GUI 的文本编辑器作为示例的主要来源,是一本值得拥有的书。

一般的“纯文本”编辑器可能使用绳索,SGI 的 STL 有一个implementation 的。基本上,它们是字符缓冲区的链接列表。这样,插入/删除字符涉及更改较小的缓冲区和一些指针,而不是将整个文档存储在单个缓冲区中并且必须移动所有内容。

【讨论】:

只有 SGI STL 实现了绳索。它们不是 C++ 标准的一部分。 对不起,我一直忘记 SGI STL 不是实际标准,我的实际标准离我不远。已更正。【参考方案3】:

这是 2008 年。不要编写文本编辑器;你正在重新发明火。

还在这里吗?我不确定这是否适用或您计划支持哪些平台,但Neatpad series of tutorials 是开始考虑编写文本编辑器的好地方。他们专注于将 Win32 作为基本平台,但其中的许多经验教训将适用于任何地方。

【讨论】:

我知道。这更像是一种智力练习,有一些小的实际用途(在我的 Nintendo DS 上放置一个文本编辑器,我已经编写了所有字体和文本 I/O 的东西)。 +1 尽管即使在 2008 年,大多数文本编辑器都很糟糕:( TextMate编辑器的程序员不听你的,赚了很多钱。【参考方案4】:

我最喜欢的解决方案是gap buffer,因为它很容易实现并且具有良好的摊销效率。只需使用单个字符数组,并将区域指定为间隙。一旦你理解了这个概念,代码几乎就自然而然地遵循了。

您还需要一个辅助数组 [vector] 来跟踪每行开头的索引——这样您就可以轻松地提取特定的文本行。辅助数组仅在间隙移动或插入/删除换行时才需要更新。

【讨论】:

【参考方案5】:

这两个在线文档为文本编辑器提供了一个小而有用的“众所周知”数据结构/技术的聚宝盆。

    Data Structures for Text Sequences 描述并通过实验分析了一些数据结构,倾向于将片表作为选择的数据结构。然而,Net.wisdom 似乎倾向于间隙缓冲区,因为它足以用于文本编辑,并且更易于实现/调试。 “文本编辑的工艺”(www.finseth.com/craft/)是较老的作品,不仅涉及数据结构,而且面向 Emacs 风格的编辑器;但这些概念通常很有用。

【讨论】:

【参考方案6】:

一种简单的方法是面向行的——将文件表示为 char/wchar_t 数组/向量的数组/向量,每行一个。插入和删除按您预期的方式工作,尽管行尾是一种特殊情况。

我会从这个开始,并可能在其他一切正常工作后用更有效地支持长行插入/删除的东西替换行数据结构。

【讨论】:

请注意,“ropes”是正确的数据结构;因为 STL 有一个,所以你应该只使用它,而不必为字符向量而烦恼。【参考方案7】:

您几乎可以使用任何数据结构来编写文本编辑器。两百万个字符是相当厚的小说的打字价值,您可以在不到十分之一秒的时间内轻松地向上/向下移动它们(对于简单数组中的插入/删除)。不要听任何人告诉你不要建造一个,你会得到在所有小细节上都完全正确的东西。

我写了我的,在我浏览了太多网页之后,我已经习惯了向上/向下翻页,就像在滚动条拇指的上方/下方单击一样。当您在普通编辑器中键入字符时,跳回到开始滚动条导航之前,这对我来说太烦人了,所以我自己写了。

如果我要进行重写(我只是对当前版本中的每个文本缓冲区使用了 delphi ansistrings,并嵌入了换行符),我会为每个字符使用整数或 int64s,并对块开始/停止、光标位置和行进行编码标记在高位,这样你在插入或删除东西时不必调整指针。

【讨论】:

【参考方案8】:

您的主要数据结构是包含文本的。您可能需要一个行数组,而不是使用长缓冲区来包含文本,因为将字符插入行中间比将字符插入大缓冲区中间更快。

您需要决定您的文本编辑器是否应该支持嵌入格式。例如,如果您需要使用字体、粗体、下划线等,那么您的数据结构将需要包含在文本中嵌入格式代码的方法。在过去 8 位字符的好日子里,我们可以使用整数的高 8 位来存储任何格式标志,而使用低 8 位来存储字符本身。

实际代码取决于您使用的语言。在 C# 或 C++ 中,您可能会为这些行使用一个字符串数组。在 C 中,您将拥有一个基于堆的字符数组。

尽可能将显示代码与文本处理代码分开。您的代码的中心将是一个紧密的循环,例如:

while (editing) 
    GetCharacter();
    ProcessCharacter();
    UpdateDisplay();

更复杂的编辑器将使用单独的线程进行字符获取/处理和显示更新。

【讨论】:

【参考方案9】:

这真的取决于您的设计。几年前,我用curses写了一个小编辑器。我使用了双向链表,其中每个节点都是一个字符(相当浪费的设计......但它使格式化和屏幕刷新例程变得非常容易)。

我的朋友使用的其他数据结构是(这是一个家庭作业项目): 1)数组的链表,每个数组代表一条线。 2)一个二维链表(只是组成那个名字)..它是一个字符的链表,但每个字符都链接到上面和下面的字符。 3)链表数组

不过,我建议你浏览一些简单的编辑器(如 pico)的源代码,看看他们使用的是什么 ds。

【讨论】:

【参考方案10】:

你查看过Scintilla的源代码吗?

【讨论】:

【参考方案11】:

查看 vim,它是开源的。在其中四处逛逛,看看它如何处理您想要的。

【讨论】:

以上是关于编辑文本缓冲区[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

文本编辑器的数据结构

linux shell 之在线文本编辑sed

第十八章 文本处理流编辑器:sed命令

Atom编辑器的并发缓冲区实现

sed文本处理工具

文本处理三剑客 sed