基于trie树的具有联想功能的文本编辑器

之前的软件设计与开发实践课程中,自己构思的大作业题目。做的具有核心功能,但是还欠缺边边角角的小功能和持久化数据结构,先放出来,有机会一点点改。github:https://github.com/chuxiuhong/smarteditor

数据结构,使用过程截图以及源代码如下:

#数据结构

**trie树**

trie树相应的介绍点击链接[https://en.wikipedia.org/wiki/Trie](https://en.wikipedia.org/wiki/Trie)

trie树在python文件中的类型定义

Node定义

#GUI设计界面

首先,用较大的文本文件进行训练,完成trie的树的训练。本文件夹下提供了一个big2.txt文件作为示例。


在之后的输入会弹出提示框

#!/usr/bin/python
# -*- coding: utf-8 -*-
import PyQt4
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.QtCore
import sys
import pickle

print ‘===================start=======================‘

class Node:
    def __init__(self):
        self.value = None
        self.children = {}  # children is of type {char, Node}
        self.fre = 0
        self.father = None

def CMP(a, b):
    return b.fre - a.fre

class Trie:
    def __init__(self):
        self.root = Node()
        self.choose = []
        self.__OpenCorrect__ = 0

    def insert(self, key):  # key is of type string
        # key should be a low-case string, this must be checked here!
        node = self.root
        for char in key:
            if char not in node.children:
                child = Node()
                node.children[char] = child
                child.value = char
                child.father = node
                node = child
            else:
                node = node.children[char]
        # node.value = key
        node.fre += 1

    def search(self, key):
        node = self.root
        for char in key:
            if char not in node.children:
                return None
            else:
                node = node.children[char]
        return node.value

    def display_node(self, node):
        if (node.value != None):
            print node.value
        for char in ‘abcdefghijklmnopqrstuvwxyz‘:
            if char in node.children:
                self.display_node(node.children[char])
        return

    def fallback(self, node):
        f_char = ‘‘
        while node != self.root:
            f_char = node.value + f_char
            node = node.father
        # print f_char
        return f_char

    def display(self):
        self.display_node(self.root)

    def find_node(self, string):
        res_node = self.root
        for i in string:
            res_node = res_node.children[i]
        return res_node

    def association(self, node):
        # 调用此函数前应该先将self.choose恢复成空列表
        if (node.value != None):
            if node.fre > 0:
                self.choose.append(node)
        for char in ‘abcdefghijklmnopqrstuvwxyz‘:
            if char in node.children:
                self.association(node.children[char])

    def output_association(self, char):
        char = str(char).lower()
        self.choose = []
        result_list = []
        self.association(self.find_node(char))
        self.choose.sort(cmp=CMP)
        if len(self.choose) > 0:
            for i in self.choose:
                result_list.append(self.fallback(i))
        if self.__OpenCorrect__ == 0:
            result_list.insert(1, self.correct(char))
            # print ‘result_list‘,result_list
        return result_list

    def correct(self, string):
        self.choose = []
        p = self.find_node(string[:-1])
        self.association(p)
        self.choose.sort(cmp=CMP)
        if len(self.choose) > 1:
            return self.fallback(self.choose[0])

def train(trie, path):
    # f = open(r‘big2.txt‘)
    f = open(path)
    word = f.read()
    f.close()
    word = word.split(‘ ‘)
    for i in word:
        trie.insert(i)

trie = Trie()
trie.__OpenCorrect__ = 0

def save_model(T):
    f1 = open("trie.pkl", ‘wb‘)
    pickle.dump(T, f1)
    f1.close()

def load_model(path):
    f2 = open(path, ‘rb‘)
    trie = pickle.load(f2)
    f2.close()

print ‘================= END =====================‘

class UI(QDialog):
    def __init__(self, parent=None):
        super(UI, self).__init__(parent)
        QSList = QStringList()
        # default
        # QSList<<‘One‘<<‘Tow‘<<‘Three‘<<‘Four‘<<‘Five‘
        # instance of Completer class
        cmp = Completer(QSList)
        global edit
        edit = TextEdit()
        edit.setFontPointSize(80)
        edit.setCompleter(cmp)
        self.setWindowTitle(u"智能文本编辑器")
        button1 = QPushButton(u"训练模型")
        button2 = QPushButton(u"保存文本文件")
        button3 = QPushButton(u"打开文本文件")
        ‘‘‘
        buttons = QushButton()
        ‘‘‘
        ‘‘‘
        定义按钮,()内为按钮名称
        ‘‘‘
        self.connect(button1, SIGNAL("clicked()"), self.get_file)
        self.connect(button2, SIGNAL("clicked()"), self.func2)
        self.connect(button3, SIGNAL("clicked()"), self.func3)
        ‘‘‘
        关联按钮与函数格式同上,触发为clicked()单击,最后一个参数为
        类内函数
        ‘‘‘
        layout = QGridLayout()
        layout.addWidget(edit, 0, 1, 1, 5)
        layout.addWidget(button1, 2, 1)
        layout.addWidget(button2, 2, 3)
        layout.addWidget(button3, 2, 5)
        ‘‘‘
        按钮布局
        ‘‘‘
        self.setLayout(layout)
        self.center()

    def center(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)

    def get_file(self):
        s = QFileDialog.getOpenFileName(self, "Open file dialog", "/", "TXT Files(*.txt)")
        train(trie, s)

    def func2(self):
        s = QFileDialog.getSaveFileName(self, "文件保存", "C:/", "All Files (*);Text Files (*.txt)")
        f = open(s, ‘w‘)
        f.write(edit.toPlainText())
        f.close()

    def func3(self):
        s = QFileDialog.getOpenFileName(self, "Open file dialog", "/", "TXT Files(*.txt)")
        f = open(s)
        edit.setText(PyQt4.QtCore.QString(f.read()))
        f.close()

class TextEdit(QTextEdit):
    def __init__(self, parent=None):
        super(TextEdit, self).__init__(parent)
        self.cmp = None
        self.p = ‘‘
        self.count = 0

    def setCompleter(self, completer):
        if self.cmp:
            self.disconnect(self.cmp, 0, 0)
        self.cmp = completer
        if (not self.cmp):
            return
        self.cmp.setWidget(self)
        self.cmp.setCompletionMode(QCompleter.PopupCompletion)
        self.cmp.setCaseSensitivity(Qt.CaseInsensitive)
        self.connect(self.cmp, SIGNAL(‘activated(QString)‘), self.insertCompletion)

    def completer(self):
        return self.cmp

    def insertCompletion(self, string):

        # get cursor position
        tc = self.textCursor()
        # selectd ranges
        tc.movePosition(QTextCursor.StartOfWord, QTextCursor.KeepAnchor)

        # replace selected ranges
        tc.insertText(string)
        self.p += str(string)
        # set cursor pos back to original pos
        self.setTextCursor(tc)

    def textUnderCursor(self):
        tc = self.textCursor()
        tc.select(QTextCursor.WordUnderCursor)
        return tc.selectedText()

    def keyPressEvent(self, e):
        ‘‘‘
        if e.key() != Qt.Key_Backspace:
            self.p = self.p + e.text()
            self.count+=1
            print ‘yes‘
        else:
            self.p = self.p[:-1]
            self.count-=1
        ‘‘‘
        print ‘p  ‘, self.p
        print ‘pressed >> ‘, e.text()
        if (self.cmp and self.cmp.popup().isVisible()):
            if e.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab, Qt.Key_Backtab):
                e.ignore()
                return

        isShortcut = ((e.modifiers() & Qt.ControlModifier) and e.key() == Qt.Key_E)
        if (not self.cmp or not isShortcut):
            super(TextEdit, self).keyPressEvent(e)

        ctrlOrShift = e.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)
        if (not self.cmp or (ctrlOrShift and e.text().isEmpty())):
            return

        eow = QString("[email protected]#$%^&*()_+{}|:\"<>?,./;‘[]\\-=")
        hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift
        completionPrefix = self.textUnderCursor()
        # hide popup while matching invalid cases
        if (not isShortcut and (hasModifier or e.text().isEmpty() or completionPrefix.length() < 1
                                or eow.contains(e.text().right(1)))):
            self.cmp.popup().hide()
            return

        self.cmp.update(completionPrefix)
        self.cmp.popup().setCurrentIndex(self.cmp.completionModel().index(0, 0))

        cr = self.cursorRect()
        cr.setWidth(self.cmp.popup().sizeHintForColumn(0)
                    + self.cmp.popup().verticalScrollBar().sizeHint().width())
        word = self.p.split(‘ ‘)[:-1]
        self.p = ‘‘
        for k in xrange(len(word)):
            self.p += word[k]
        print ‘self.p=‘, self.p
        self.cmp.complete(cr)

class Completer(QCompleter):
    def __init__(self, stringlist, parent=None):
        super(Completer, self).__init__(parent)
        self.stringlist = stringlist
        self.setModel(QStringListModel())

    # update function will trigger while the text has been modified
    def update(self, completionText):
        # generate a new QStringList instance
        qsList = QStringList()

        # generate hint lists which returns by customatic definitions
        newList = genMyStrList(completionText)
        for item in newList:
            qsList.append(item)

        self.stringlist = qsList
        # filteredList = self.stringlist.filter(completionText, Qt.CaseInsensitive)
        self.model().setStringList(self.stringlist)
        self.popup().setCurrentIndex(self.model().index(0, 0))

# the function below defined a way to generate a string list
def genMyStrList(key):
    my_str_list = trie.output_association(key)
    return my_str_list

def main():
    app = QApplication(sys.argv)
    app.processEvents()
    form = UI()
    form.show()
    # splash.finish(form)
    app.exec_()
    window = QMainWindow()
    window.statusBar().showMessage(‘Yuan Ziqi‘)
    menubar = window.menuBar

    window.setWindowTitle(‘Auto Complete Demo‘)
    window.resize(400, 200)
    window.move(400, 100)

    edit = TextEdit()
    edit.setFontPointSize(40)
    edit.setCompleter(cmp)
    # bt = addbutton()
    # window.addDockWidget(bt)
    window.setCentralWidget(edit)
    window.show()
    sys.exit(app.exec_())

if __name__ == ‘__main__‘:
    print ‘app is running successfully‘
    main()
时间: 2024-11-07 15:25:15

基于trie树的具有联想功能的文本编辑器的相关文章

基于 trie 树的最长匹配分词测试

测试一个基于trie树的分词,没有应用任何统计模型,分词的效率估计会很高但是分词准确率很差. reference http://www.hankcs.com/program/java/tire-tree-participle.html https://github.com/ansjsun/tree_split

Trie树的详解及应用

Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高.Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie 的强大之处就在于它的时间复杂度.它的插入和查询时间复杂度都为 O(k) ,其中 k 为 key 的长度,与 Trie 中保存了多少个元素无关.Hash 表号称是

LeetCode Implement Trie (Prefix Tree) (实现trie树3个函数:插入,查找,前缀)

题意:实现trie树的3个功能,只含小写字母的串. 思路:老实做即可! 1 class TrieNode { 2 public: 3 TrieNode* chd[26]; 4 bool flag; 5 // Initialize your data structure here. 6 TrieNode() { 7 memset(chd,0,sizeof(chd)); 8 flag=0; 9 } 10 11 }; 12 13 class Trie { 14 public: 15 Trie() {

Ansj分词双数组Trie树实现与arrays.dic词典格式

http://www.hankcs.com/nlp/ansj-word-pairs-array-tire-tree-achieved-with-arrays-dic-dictionary-format.html arrays.dic是一个双数组Trie树格式的词典,用文本的形式储存了索引,字串,base,check,status与词性. 一个直观的图示: index就是base数组中的下标. term是词的当前状态,不一定代表一个词,如“一举一”是“一举一动”的前缀. base是base数组的值

Hihocoder #1014 : Trie树 (字典数树统计前缀的出现次数 *【模板】 基于指针结构体实现 )

#1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一本词典,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能对于每一个我给出的字符串,都在这个词典里面找到以这个字符串开头的所有单词呢?” 身经百战的小Ho答道:“怎么会不能呢!你每给我一个字符串,我就依次遍历词典里的所有单词,检查你给我的字

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

Trie树详解(转)

特别声明 本文只是一篇笔记类的文章,所以不存在什么抄袭之类的. 以下为我研究时参考过的链接(有很多,这里我只列出我记得的): Trie(字典树)的应用--查找联系人 trie树 Trie树:应用于统计和排序 牛人源码,研究代码来源 1.字典树的概念 字典树,因为它的搜索快捷的特性被单词搜索系统使用,故又称单词查找树.它是一种树形结构的数据结构.之所以快速,是因为它用空间代替了速度. 2.字典树的特点: 字典树有三个基本性质: 1.根节点不包含字符,除根节点外每一个节点都只包含一个字符2.从根节点

B树、Trie树详解

查找(二) 散列表 散列表是普通数组概念的推广.由于对普通数组可以直接寻址,使得能在O(1)时间内访问数组中的任意位置.在散列表中,不是直接把关键字作为数组的下标,而是根据关键字计算出相应的下标. 使用散列的查找算法分为两步.第一步是用散列函数将被查找的键转化为数组的一个索引. 我们需要面对两个或多个键都会散列到相同的索引值的情况.因此,第二步就是一个处理碰撞冲突的过程,由两种经典解决碰撞的方法:拉链法和线性探测法. 散列表是算法在时间和空间上作出权衡的经典例子. 如果没有内存限制,我们可以直接

java实现的Trie树数据结构

最近在学习的时候,经常看到使用Trie树数据结构来解决问题,比如" 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M.返回频数最高的100个词." 该如何解决? 有一种方案就是使用Trie树加 排序实现 . 什么是Trie 树呢?也就是常说的字典树,网上对此讲得也很多,简单补充一下个人理解: 它实际上相当于把单词的公共部分给拎出来,这样一层一层往上拎直到得到每个节点都是不可分的最小单元! 比如网上一个例子 一组单词,inn, int, at, a