Синонимайзер (PyQt4)

Понедельник, Апрель 12, 2010 г.
Мне очень нравится язык программирования Python. Конечно он несравним по быстродействию с Сишным семейством и с популярным Java. Скриптовость, динамическая типизация... Но всё это с лихвой окупается скоростью разработки из-за простоты синтаксиса и лаконичности получаемого кода. Более того - писать на Python приятно ;).
Появилась необходимость облегчить работу нашего копирайтера, написать программу подбирающую синонимы к введённому слову. В виде отступления хочу заметить что наш копирайтер работает в linux (KDE4) и потому выбор графической библиотеки пал на Qt. Несмотря на то что в стандартной библиотеке Python есть поддержка Tk, Qt мне нравится больше по многим причинам.
Графический интерфейс я создавал с помощью Qt Designer. Полученный результат сохранил в файл ui формата xml. Далее утилитой pyuic4 получил Python класс осуществляющий отрисовку графики.
pyuic face.ui -o face.py

Полученный класс я малость подредактировал и в итоге получил вот такой код:
# -*- coding: utf-8 -*-

from PyQt4 import QtCore, QtGui

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(501, 270)
        MainWindow.setMinimumSize(QtCore.QSize(501, 270))
        MainWindow.setMaximumSize(QtCore.QSize(501, 270))
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.lineEdit = QtGui.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(10, 20, 481, 26))
        self.lineEdit.setObjectName("lineEdit")
        self.textEdit = QtGui.QTextEdit(self.centralwidget)
        self.textEdit.setGeometry(QtCore.QRect(10, 60, 481, 191))
        self.textEdit.setObjectName("textEdit")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "Синонимайзер", None, QtGui.QApplication.UnicodeUTF8))

Как видите всё достаточно просто. Примитивное окно с QLineEdit и QTextEdit. Сохраняя эргономичный вид я обошёлся без кнопок использовав сигнал returnPressed() для поиска синонимов. Выглядит это так:

синонимайзер

Интерфейс у нас готов, теперь напишем само приложение. У вас наверно возник вопрос, откуда будут браться синонимы. Погуглив немного я нашёл словарь синонимов в текстовом формате. После нехитрых манипуляций при помощи всё того же Python и его мощного инструментария по работе с текстовыми данными я привёл найденный словарь в удобный для работы программой вид. Файл будет называться sinonim.
абитуриент|ученик,претендент,поступающий,выпускник
аблактирование|аблактировка,прививка,сращивание,прививание
аблактированный|сращенный,привитый
аблактироваться|прививаться,сращиваться
аблактируемый|прививаемый,сращиваемый
аблатив|аблятив,падеж
аблаут|абляут,чередование
абляция|унос,снос
або|альбо,ли,либо,или,аль,разве,нежто
Абов|любовь Божия
аболиция|прекращение,отмена

Структура нехитрая, каждая группа в отдельной строке, искомое слово отделено от вариантов прямым слэшем '|', варианты через запятую.
Далее рассмотрим код программы.
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from os import path, curdir
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from face import Ui_MainWindow

class Sinonim(QMainWindow, Ui_MainWindow):

    def __init__(self, parent=None):
        super(Sinonim, self).__init__(parent)
        self.setupUi(self)

        # выбираем синонимы из файла
        file_path = path.join(path.abspath(curdir), path.dirname(__file__))+'/sinonim'
        self.sinonim = {}
        with open (file_path) as fp:
            for line in fp:
                line = line.decode('utf-8')
                bla = line.split(u'|')
                self.sinonim[bla[0]] = bla[1]

        # сигналы
        QObject.connect(self.lineEdit, SIGNAL("returnPressed()"), self.find)

    def find(self):
        """поиск и вывод синонима"""
        word = unicode(self.lineEdit.text())
        result = ''
        if self.sinonim.has_key(word):
            result = self.sinonim[word]
        self.textEdit.setPlainText(result)

app = QApplication(sys.argv)
obj = Sinonim()
obj.show()
app.exec_()

Подключаем библиотеки и наш интерфейс, далее создаём класс потомок QMainWindow и созданного интерфейса Ui_MainWindow. Запускаем конструкторы родителей. Вешаем на сигнал returnPressed() компонента QLineEdit обработчик, метод find в котором собственно и осуществляем поиск и вывод синонимов. Результат работы:

синонимайзер в работе

Вот и всё. Тут можно взять готовый вариант. Для работы необходим Python 2.6 и PyQt4.
Считаю необходимым предупредить, что входящий в состав синонимайзера словарь содержит элементы ненормативной лексики.
Теги: PythonQtgui
 
   
Комментарии (6)
Vzlom
13.04.2010 в 19:27
По поводу быстродействия, разве ява быстрее питона?
demoriz
14.04.2010 в 5:17
Значительно быстрее. Сам замерял скорость отработки программ основанных на одних и тех же алгоритмах. Да и в интернете примеров достаточно. Java уступает Сям и то не во всём и в основном лишь из за возможности в Сях практически напрямую работать с памятью самостоятельно решаю в какой области создавать объект или переменную. Вот с GUI Java на слабых машинах подтормаживает но это из-за того что Java машина жрёт много памяти. PyQt всё же может работать быстрее аналогичных Java приложений но это благодаря Qt.
nldl
15.04.2010 в 23:03
а самого словарика синонимов в таком формате у вас нет? Был бы очень признателен если бы вы им поделились.
demoriz
16.04.2010 в 6:47
Скачайте сам синонимайзер, в архиве будет словарь в виде обычного текстового файла.
Виталий
31.12.2010 в 23:26
Вместо
20	            fpl = fp.readlines()
21	            for line in fpl:

разве не лучше
20	            for line in fp:

?
В любом случае Python поощряет использовать итераторы везде, где не требуются все данные сразу. У Вас список fpl далее не используется нигде, кроме цикла. Если вспомнить, что for работает с итераторами, то станет ясно, что fpl лишняя сущность. Поэтому хотя бы
fp.xreadlines()

, но в моём первом варианте то же самое сделает сам цикл.
demoriz
29.01.2011 в 15:45
Да действительно. Не могу не согласиться, список fpl лишний. Я до сего момента даже не подозревал что файловый дескриптор можно использовать как итератор. Спасибо за замечание, исправлю код в посте.
Оставить комментарий   Нажмите, чтобы отменить ответ.
Доступен html впределах разумного. Для цитирования используйте <blockquote></blockquote>, для отрисовки программного кода [code][/code].
Для всяких хакеров и прочих: комментарии проходят санитизацию, всё лишнее будет вырезано. Так что не тратьте своё драгоценное время.
Имя (обязательно)
E-Mail (Не будет опубликован , обязательно)
Сайт (необязательно)