python数据结构学习笔记-2016-11-09-01-文本编辑器
2016-11-09 20:56
579 查看
9.5 应用:文本编辑器
本节将多重链表应用于编辑缓冲ADT(Edit Buffer ADT)。
9.5.1 编辑操作
布局
通常将文本以行和列的形式组织起来。每一行有无限的长度,每一行的大小可能不同,但末尾都有换行符。一个空的文本,只有一行空行以及一个换行符。
文本光标
文本光标由行号以及字符的偏移量(应该就是列号)来决定,其可以在文本的任何区域内移动,但只限于当前位置存在字符的情况下。文本光标的移动至少要有以下三种:
竖直移动,即移动到另外移动相同偏移量的位置,如果移动到的行较短,则移至该行末尾;
水平移动,即在一行内向前或向后移动,在移动到一行的起始字符之前时,自动将光标移至上一行末尾,在移动到一行的结尾字符之后时,自动将光标移至下一行的起始位置;
移动至文件首尾或者行首尾。
插入文本
有两种模式,分别为插入模式和改写模式。在插入模式的情况下,文本光标之后直至该行换行符之前的字符都向后移动,再在文本光标右侧插入字符,随着字符的插入,文本光标也向后移动。在改写模式下,将文本光标右侧紧邻的字符替换,也是随着字符替换的进行,文本光标也随之向后移动。
此外,还需考虑换行符的问题,在换行符前插入字符,则该行自动延伸;在换行符之后插入字符,即在下一行的起始字符之前插入字符;当插入一个换行符时,当前行分为两半,在文本光标之前的算作新的一行,在文本光标之后到原来行的换行符之前也是新的一行。
删除文本
分为删除操作和擦掉操作(rub-out),分别对应于键盘上的Delete和Backspace。删除操作,文本光标所在的字符被删除,光标位置不变;而擦掉操作,则是文本光标之前的一个字符被删除,光标位置向前移动一个位置。
与插入文本类似,删除文本也要考虑换行符的问题。删除换行符时,当前行与下一行合并成一行。
9.5.2 编辑缓冲ADT
应具有如下方法:
EditBuffer():创建空文档,含有一个空行以及一个换行符,此时文本光标处于空行的起始位置,输入模式是插入模式;
numLines():返回总行数;
numChars():返回文本光标所在行的字符数(包括换行符);
lineIndex():返回文本光标所在行的行号;
columnIndex():返回文本光标所在列的列号;
setEntryMode(insert):设定输入模式,根据insert是True还是False,确定输入模式是插入模式还是改写模式;
toggleEntryMode():切换输入模式,根据当前输入模式来改变;
inInsertMode():确定当前输入模式是否是插入模式;
getChar():返回文本光标所在位置的字符;
getLine():返回文本光标所在行的所有内容(包括换行符),以字符串形式返回;
moveUp(num):文本光标的竖直移动,如前所述,若num为负,文本光标不移动;
moveDown(num):同上,方向相反;
moveDocHome():将文本光标移至文档开头;
moveDocEnd():将文本光标移至文档结尾;
moveLeft():文本光标的水平移动,如前所述;
moveRight():同上,方向相反;
moveLineHome():将文本光标移动至当前行的开头;
moveLineEnd():将文本光标移动至当前行的结尾;
breakLine():在文本光标位置另起一行,如前所述,当插入换行符时,文本光标之后到原来的换行符之前的字符组成新的一行,文本光标也移动至该行起始位置;
deleteLine():删除文本光标所在行的所有内容,文本光标移动至下一行的起始位置,如果删除的是最后一行,文本光标则移动至上一行的末尾;
truncateLine():删除文本光标所在行,从文本光标位置起到该行结束前的所有字符,换行符不删除,文本光标移动至该行末尾;
addChar(char):将字符char插入,根据输入模式来进行,另外还要考虑此时文本光标位置和插入字符是否是换行符的问题,如前所述;
deleteChar():按删除模式,将文本光标所在位置的字符删除,文本光标位置不变;
ruboutChar():按擦除模式,将文本光标之前的字符删除,文本光标向前移动一个位置,注意删除的是换行符的情况;
deleteAll():将文本所有字符删除,返回至空文本状态(一个空行和一个换行符)。
9.5.3 实现
我们使用python列表的双链表来实现,每一行的内容都储存在一个python列表中,而这一个python列表都储存在双链表的一个结点中,如下图所示:
构造器,创建空文档,并初始化各参数,_firstLine和_lastLine分别是双链表的头指针和尾指针,分别代表着文档的第一行和最后一行。_curLine和_curColNdx则决定着文档光标的位置,前者决定文本光标所在行,后者决定文本光标所在列。_numLines记录文档当前总行数,_insertMode记录当前输入模式是否是插入模式。
文本光标移动,注意不要超过范围。
修改缓冲区,即编辑文档,具体包括插入字符和删除字符,注意换行符的问题。
最后要注意breakLine()方法,其目的是在文本光标当前所在处另起一行,将该行之后的文本全部转移至新的一行。
本节将多重链表应用于编辑缓冲ADT(Edit Buffer ADT)。
9.5.1 编辑操作
布局
通常将文本以行和列的形式组织起来。每一行有无限的长度,每一行的大小可能不同,但末尾都有换行符。一个空的文本,只有一行空行以及一个换行符。
文本光标
文本光标由行号以及字符的偏移量(应该就是列号)来决定,其可以在文本的任何区域内移动,但只限于当前位置存在字符的情况下。文本光标的移动至少要有以下三种:
竖直移动,即移动到另外移动相同偏移量的位置,如果移动到的行较短,则移至该行末尾;
水平移动,即在一行内向前或向后移动,在移动到一行的起始字符之前时,自动将光标移至上一行末尾,在移动到一行的结尾字符之后时,自动将光标移至下一行的起始位置;
移动至文件首尾或者行首尾。
插入文本
有两种模式,分别为插入模式和改写模式。在插入模式的情况下,文本光标之后直至该行换行符之前的字符都向后移动,再在文本光标右侧插入字符,随着字符的插入,文本光标也向后移动。在改写模式下,将文本光标右侧紧邻的字符替换,也是随着字符替换的进行,文本光标也随之向后移动。
此外,还需考虑换行符的问题,在换行符前插入字符,则该行自动延伸;在换行符之后插入字符,即在下一行的起始字符之前插入字符;当插入一个换行符时,当前行分为两半,在文本光标之前的算作新的一行,在文本光标之后到原来行的换行符之前也是新的一行。
删除文本
分为删除操作和擦掉操作(rub-out),分别对应于键盘上的Delete和Backspace。删除操作,文本光标所在的字符被删除,光标位置不变;而擦掉操作,则是文本光标之前的一个字符被删除,光标位置向前移动一个位置。
与插入文本类似,删除文本也要考虑换行符的问题。删除换行符时,当前行与下一行合并成一行。
9.5.2 编辑缓冲ADT
应具有如下方法:
EditBuffer():创建空文档,含有一个空行以及一个换行符,此时文本光标处于空行的起始位置,输入模式是插入模式;
numLines():返回总行数;
numChars():返回文本光标所在行的字符数(包括换行符);
lineIndex():返回文本光标所在行的行号;
columnIndex():返回文本光标所在列的列号;
setEntryMode(insert):设定输入模式,根据insert是True还是False,确定输入模式是插入模式还是改写模式;
toggleEntryMode():切换输入模式,根据当前输入模式来改变;
inInsertMode():确定当前输入模式是否是插入模式;
getChar():返回文本光标所在位置的字符;
getLine():返回文本光标所在行的所有内容(包括换行符),以字符串形式返回;
moveUp(num):文本光标的竖直移动,如前所述,若num为负,文本光标不移动;
moveDown(num):同上,方向相反;
moveDocHome():将文本光标移至文档开头;
moveDocEnd():将文本光标移至文档结尾;
moveLeft():文本光标的水平移动,如前所述;
moveRight():同上,方向相反;
moveLineHome():将文本光标移动至当前行的开头;
moveLineEnd():将文本光标移动至当前行的结尾;
breakLine():在文本光标位置另起一行,如前所述,当插入换行符时,文本光标之后到原来的换行符之前的字符组成新的一行,文本光标也移动至该行起始位置;
deleteLine():删除文本光标所在行的所有内容,文本光标移动至下一行的起始位置,如果删除的是最后一行,文本光标则移动至上一行的末尾;
truncateLine():删除文本光标所在行,从文本光标位置起到该行结束前的所有字符,换行符不删除,文本光标移动至该行末尾;
addChar(char):将字符char插入,根据输入模式来进行,另外还要考虑此时文本光标位置和插入字符是否是换行符的问题,如前所述;
deleteChar():按删除模式,将文本光标所在位置的字符删除,文本光标位置不变;
ruboutChar():按擦除模式,将文本光标之前的字符删除,文本光标向前移动一个位置,注意删除的是换行符的情况;
deleteAll():将文本所有字符删除,返回至空文本状态(一个空行和一个换行符)。
9.5.3 实现
我们使用python列表的双链表来实现,每一行的内容都储存在一个python列表中,而这一个python列表都储存在双链表的一个结点中,如下图所示:
#-*-coding: utf-8-*- # 编辑缓冲ADT class EditBuffer(object): # 创建空文档 def __init__(self): self._firstLine = _EditBufferNode(['\n']) # 双链表的头指针 self._lastLine = self._firstLine # 双链表的尾指针 self._curLine = self._firstLine # 文本光标所在行,其实质是双链表中的外部指针 self._curLineNdx = 0 # 文本光标所在行行号 self._curColNdx = 0 # 文本光标所在列列号,其实质是python列表的索引 self._numLines = 1 # 记录文本当前总行数 self._insertMode = True # 当前输入模式是否是插入模式 # 返回总行数 def numLines(self): return self._numLines # 返回文本光标所在行的字符数 def numChars(self): return len(self._curLine.text) # 返回文本光标所在行的行号 def lineIndex(self): return self._curLineNdx # 返回文本光标所在列的列号 def columnIndex(self): return self._curColNdx # 设定输入模式,根据insert是True还是False,选择输入模式 def setEntryMode(self, insert): self._insertMode = insert # 切换输入模式 def toggleEntryMode(self): self._insertMode = not self._insertMode # 判断输入模式是否是插入模式 def inInsertMode(self): return self._insertMode == True # 返回文本光标所在位置的字符 def getChar(self): return self._curLine.text[self._curColNdx] # 返回文本光标所在行的内容,以字符串形式返回 def getLine(self): lineStr = '' for char in self._curLine.text: lineStr += char return lineStr # 文本光标向上移动 def moveUp(self, nlines): if nlines <= 0: # 移动行数必须是正数 return elif self._curLineNdx - nlines < 0: # 向上移动不能超过第一行 nlines = _curLineNdx for i in range(nlines): self._curLine = self._curLine.prev # 向上移动 self._curLineNdx -= nlines # 行号也随之调整 if self._curColNdx >= self.numChars(): # 要移动到的行,其总字符数小于文本光标所在列号,自动将文本光标移动至行末尾。 self.moveLineEnd() # 文本光标向左移动 def moveLeft(self): if self._curColNdx == 0: # 此时文本光标处于一行的开头,文本光标移动至上一行末尾 if self._curLineNdx > 0: self.moveUp(1) self.moveLineEnd() else: self._curColNdx -= 1 # 将文本光标移动至文档开头 def moveLineHome(self): self._curColNdx = 0 # 将文本光标移动至文档末尾 def moveLineEnd(self): self._curColNdx = self.numChars() - 1 # 从文本光标另起一行 def breakLine(self): nlContents = self._curLine.text[self._curColNdx:] del self._curLine.text[self._curColNdx:] self._curLine.text.append('\n') self._insertNode(self._curLine, nlContents) self._curLine = newLine self._curLineNdx += 1 self._curColNdx = 0 # 输入字符,注意换行符 def addChar(self, char): if char == '\n': self.breakLine() else: ndx = self._curColNdx if self.inInsertMode(): self._curLine.text.insert(ndx, char) else: if self.getChar() == '\n': # 换行符不能被改写 self._curLine.text.insert(ndx, char) else: self._curLine.text[ndx] = char self._curColNdx += 1 # 删除文本光标之前的字符 def deleteChar(self): if self.getChar() != '\n': self._curLine.text.pop(self._curColNdx) else: if self._curLine is self._lastLine: return else: nextLine = self._curLine.next self._curLine.text.pop() self._curLine.text.extend(nextLine.text) self._removeNode(nextLine) class _EditBufferNode(object): def __init__(self, text): self.text = text self.prev = None self.next = None
构造器,创建空文档,并初始化各参数,_firstLine和_lastLine分别是双链表的头指针和尾指针,分别代表着文档的第一行和最后一行。_curLine和_curColNdx则决定着文档光标的位置,前者决定文本光标所在行,后者决定文本光标所在列。_numLines记录文档当前总行数,_insertMode记录当前输入模式是否是插入模式。
文本光标移动,注意不要超过范围。
修改缓冲区,即编辑文档,具体包括插入字符和删除字符,注意换行符的问题。
最后要注意breakLine()方法,其目的是在文本光标当前所在处另起一行,将该行之后的文本全部转移至新的一行。
相关文章推荐
- python数据结构学习笔记-2016-11-11-01-递归
- python数据结构学习笔记-2016-11-18-01-散列表ADT
- python数据结构学习笔记-2016-12-03-01-堆排序
- python数据结构学习笔记-2016-11-02-01-栈的应用
- python数据结构学习笔记-2016-10-22-01-评价python列表
- python数据结构学习笔记-2016-10-15-01-矩阵ADT
- python数据结构学习笔记-2016-10-07-01-完善后的mydate.py
- python数据结构学习笔记-2016-11-23-01-归并排序
- python数据结构学习笔记-2016-11-27-01-二叉树
- python数据结构学习笔记-2016-11-24-01-快速排序
- python数据结构学习笔记-2016-10-24-01-排序列表
- python数据结构学习笔记-2016-10-17-01-集合
- python数据结构学习笔记-2016-11-30-01-堆
- python数据结构学习笔记-2016-11-28-01-表达式树
- python数据结构学习笔记-2016-11-26-01-链表排序
- python数据结构学习笔记-2016-12-04-01-Morse电码
- python数据结构学习笔记-2016-11-20-01-直方图ADT
- python数据结构学习笔记-2016-11-07-01-双链表
- python数据结构学习笔记-2016-10-27-01-链表
- python数据结构学习笔记-2016-10-05-01-抽象数据类型(一)