import sys import re from PyQt5.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QListWidget, QTextEdit, QPushButton, QComboBox, QRadioButton, QCheckBox, QLabel, QLineEdit, QFileDialog, QMessageBox, QInputDialog, QButtonGroup, QFrame ) from PyQt5.QtCore import Qt class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Лабораторная работа №1 - Обработка текста") self.setMinimumSize(900, 700) # Главный виджет central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QVBoxLayout(central_widget) # === Верхняя часть: работа с файлом и критерии === top_group = QGroupBox("Работа с файлом") top_layout = QHBoxLayout(top_group) # Кнопки файла self.btn_open = QPushButton("Открыть файл") self.btn_open.clicked.connect(self.open_file) top_layout.addWidget(self.btn_open) # Критерии отбора (RadioButton) criteria_group = QGroupBox("Критерий отбора") criteria_layout = QVBoxLayout(criteria_group) self.radio_group = QButtonGroup() self.radio_all = QRadioButton("Все") self.radio_digits = QRadioButton("Содержащие цифры") self.radio_email = QRadioButton("Содержащие e-mail") self.radio_all.setChecked(True) self.radio_group.addButton(self.radio_all, 0) self.radio_group.addButton(self.radio_digits, 1) self.radio_group.addButton(self.radio_email, 2) criteria_layout.addWidget(self.radio_all) criteria_layout.addWidget(self.radio_digits) criteria_layout.addWidget(self.radio_email) top_layout.addWidget(criteria_group) # Кнопка "Начать" self.btn_start = QPushButton("Начать") self.btn_start.clicked.connect(self.process_text) top_layout.addWidget(self.btn_start) top_layout.addStretch() main_layout.addWidget(top_group) # === RichTextBox (QTextEdit) === text_group = QGroupBox("Исходный текст") text_layout = QVBoxLayout(text_group) self.text_edit = QTextEdit() self.text_edit.setPlaceholderText("Откройте текстовый файл или введите текст...") text_layout.addWidget(self.text_edit) main_layout.addWidget(text_group) # === Средняя часть: два раздела с панелью управления === middle_layout = QHBoxLayout() # Раздел 1 section1_group = QGroupBox("Раздел 1") section1_layout = QVBoxLayout(section1_group) self.list1 = QListWidget() self.list1.setSelectionMode(QListWidget.ExtendedSelection) section1_layout.addWidget(self.list1) # Сортировка для раздела 1 sort1_layout = QHBoxLayout() sort1_layout.addWidget(QLabel("Сортировка:")) self.combo_sort1 = QComboBox() self.combo_sort1.addItems([ "По длине (возр.)", "По длине (убыв.)", "По алфавиту (возр.)", "По алфавиту (убыв.)" ]) sort1_layout.addWidget(self.combo_sort1) self.btn_sort1 = QPushButton("Сортировать") self.btn_sort1.clicked.connect(lambda: self.sort_list(self.list1, self.combo_sort1)) sort1_layout.addWidget(self.btn_sort1) section1_layout.addLayout(sort1_layout) self.btn_clear1 = QPushButton("Очистить") self.btn_clear1.clicked.connect(lambda: self.list1.clear()) section1_layout.addWidget(self.btn_clear1) middle_layout.addWidget(section1_group) # Панель управления (между разделами) control_panel = QFrame() control_panel.setFrameStyle(QFrame.StyledPanel) control_layout = QVBoxLayout(control_panel) self.btn_move_right = QPushButton("→") self.btn_move_right.setToolTip("Переместить выбранные в Раздел 2") self.btn_move_right.clicked.connect(self.move_selected_right) self.btn_move_all_right = QPushButton("⇒") self.btn_move_all_right.setToolTip("Переместить все в Раздел 2") self.btn_move_all_right.clicked.connect(self.move_all_right) self.btn_move_left = QPushButton("←") self.btn_move_left.setToolTip("Переместить выбранные в Раздел 1") self.btn_move_left.clicked.connect(self.move_selected_left) self.btn_move_all_left = QPushButton("⇐") self.btn_move_all_left.setToolTip("Переместить все в Раздел 1") self.btn_move_all_left.clicked.connect(self.move_all_left) self.btn_add = QPushButton("Добавить") self.btn_add.clicked.connect(self.add_item) self.btn_delete = QPushButton("Удалить") self.btn_delete.clicked.connect(self.delete_selected) control_layout.addStretch() control_layout.addWidget(self.btn_move_right) control_layout.addWidget(self.btn_move_all_right) control_layout.addWidget(self.btn_move_left) control_layout.addWidget(self.btn_move_all_left) control_layout.addSpacing(20) control_layout.addWidget(self.btn_add) control_layout.addWidget(self.btn_delete) control_layout.addStretch() middle_layout.addWidget(control_panel) # Раздел 2 section2_group = QGroupBox("Раздел 2") section2_layout = QVBoxLayout(section2_group) self.list2 = QListWidget() self.list2.setSelectionMode(QListWidget.ExtendedSelection) section2_layout.addWidget(self.list2) # Сортировка для раздела 2 sort2_layout = QHBoxLayout() sort2_layout.addWidget(QLabel("Сортировка:")) self.combo_sort2 = QComboBox() self.combo_sort2.addItems([ "По длине (возр.)", "По длине (убыв.)", "По алфавиту (возр.)", "По алфавиту (убыв.)" ]) sort2_layout.addWidget(self.combo_sort2) self.btn_sort2 = QPushButton("Сортировать") self.btn_sort2.clicked.connect(lambda: self.sort_list(self.list2, self.combo_sort2)) sort2_layout.addWidget(self.btn_sort2) section2_layout.addLayout(sort2_layout) self.btn_clear2 = QPushButton("Очистить") self.btn_clear2.clicked.connect(lambda: self.list2.clear()) section2_layout.addWidget(self.btn_clear2) # Кнопка сохранения self.btn_save = QPushButton("Сохранить в файл") self.btn_save.clicked.connect(self.save_file) section2_layout.addWidget(self.btn_save) middle_layout.addWidget(section2_group) main_layout.addLayout(middle_layout) # === Нижняя часть: поиск === search_group = QGroupBox("Поиск") search_layout = QHBoxLayout(search_group) search_layout.addWidget(QLabel("Искать:")) self.search_input = QLineEdit() self.search_input.setPlaceholderText("Введите текст для поиска...") search_layout.addWidget(self.search_input) # CheckBox для выбора раздела поиска self.check_search1 = QCheckBox("В разделе 1") self.check_search1.setChecked(True) self.check_search2 = QCheckBox("В разделе 2") self.check_search2.setChecked(True) search_layout.addWidget(self.check_search1) search_layout.addWidget(self.check_search2) self.btn_search = QPushButton("Найти") self.btn_search.clicked.connect(self.search_items) search_layout.addWidget(self.btn_search) self.btn_reset_search = QPushButton("Сбросить") self.btn_reset_search.clicked.connect(self.reset_search) search_layout.addWidget(self.btn_reset_search) main_layout.addWidget(search_group) def open_file(self): """Открыть текстовый файл""" file_path, _ = QFileDialog.getOpenFileName( self, "Открыть файл", "", "Текстовые файлы (*.txt);;Все файлы (*)" ) if file_path: try: with open(file_path, 'r', encoding='utf-8') as f: self.text_edit.setText(f.read()) except Exception as e: QMessageBox.critical(self, "Ошибка", f"Не удалось открыть файл:\n{e}") def process_text(self): """Обработать текст и заполнить Раздел 1""" text = self.text_edit.toPlainText() if not text.strip(): QMessageBox.warning(self, "Внимание", "Текст пуст!") return # Разбиваем на слова words = re.findall(r'\S+', text) # Фильтруем по критерию criteria = self.radio_group.checkedId() filtered_words = [] for word in words: if criteria == 0: # Все filtered_words.append(word) elif criteria == 1: # Содержащие цифры if re.search(r'\d', word): filtered_words.append(word) elif criteria == 2: # Содержащие e-mail if re.search(r'[\w.-]+@[\w.-]+\.\w+', word): filtered_words.append(word) # Заполняем ListBox self.list1.clear() self.list1.addItems(filtered_words) QMessageBox.information( self, "Готово", f"Найдено слов: {len(filtered_words)}" ) def move_selected_right(self): """Переместить выбранные элементы из Раздела 1 в Раздел 2""" selected = self.list1.selectedItems() for item in selected: self.list2.addItem(item.text()) self.list1.takeItem(self.list1.row(item)) def move_all_right(self): """Переместить все элементы из Раздела 1 в Раздел 2""" while self.list1.count() > 0: item = self.list1.takeItem(0) self.list2.addItem(item.text()) def move_selected_left(self): """Переместить выбранные элементы из Раздела 2 в Раздел 1""" selected = self.list2.selectedItems() for item in selected: self.list1.addItem(item.text()) self.list2.takeItem(self.list2.row(item)) def move_all_left(self): """Переместить все элементы из Раздела 2 в Раздел 1""" while self.list2.count() > 0: item = self.list2.takeItem(0) self.list1.addItem(item.text()) def add_item(self): """Добавить новый элемент""" text, ok = QInputDialog.getText(self, "Добавить элемент", "Введите слово:") if ok and text.strip(): # Спрашиваем куда добавить items = ["Раздел 1", "Раздел 2"] choice, ok = QInputDialog.getItem( self, "Выбор раздела", "Куда добавить?", items, 0, False ) if ok: if choice == "Раздел 1": self.list1.addItem(text.strip()) else: self.list2.addItem(text.strip()) def delete_selected(self): """Удалить выбранные элементы из обоих разделов""" # Удаляем из раздела 1 for item in self.list1.selectedItems(): self.list1.takeItem(self.list1.row(item)) # Удаляем из раздела 2 for item in self.list2.selectedItems(): self.list2.takeItem(self.list2.row(item)) def sort_list(self, list_widget, combo_box): """Сортировка списка выбранным алгоритмом (пузырьковая сортировка)""" # Получаем все элементы items = [list_widget.item(i).text() for i in range(list_widget.count())] if not items: return sort_type = combo_box.currentIndex() # Пузырьковая сортировка n = len(items) for i in range(n): for j in range(0, n - i - 1): should_swap = False if sort_type == 0: # По длине (возр.) should_swap = len(items[j]) > len(items[j + 1]) elif sort_type == 1: # По длине (убыв.) should_swap = len(items[j]) < len(items[j + 1]) elif sort_type == 2: # По алфавиту (возр.) should_swap = items[j].lower() > items[j + 1].lower() elif sort_type == 3: # По алфавиту (убыв.) should_swap = items[j].lower() < items[j + 1].lower() if should_swap: items[j], items[j + 1] = items[j + 1], items[j] # Обновляем список list_widget.clear() list_widget.addItems(items) def search_items(self): """Поиск элементов в разделах""" search_text = self.search_input.text().lower() if not search_text: return found_count = 0 # Поиск в разделе 1 if self.check_search1.isChecked(): for i in range(self.list1.count()): item = self.list1.item(i) if search_text in item.text().lower(): item.setSelected(True) found_count += 1 else: item.setSelected(False) # Поиск в разделе 2 if self.check_search2.isChecked(): for i in range(self.list2.count()): item = self.list2.item(i) if search_text in item.text().lower(): item.setSelected(True) found_count += 1 else: item.setSelected(False) QMessageBox.information(self, "Результат поиска", f"Найдено элементов: {found_count}") def reset_search(self): """Сбросить поиск""" self.search_input.clear() self.list1.clearSelection() self.list2.clearSelection() def save_file(self): """Сохранить содержимое Раздела 2 в файл""" if self.list2.count() == 0: QMessageBox.warning(self, "Внимание", "Раздел 2 пуст!") return file_path, _ = QFileDialog.getSaveFileName( self, "Сохранить файл", "", "Текстовые файлы (*.txt)" ) if file_path: try: with open(file_path, 'w', encoding='utf-8') as f: items = [self.list2.item(i).text() for i in range(self.list2.count())] f.write('\n'.join(items)) QMessageBox.information(self, "Успех", "Файл сохранён!") except Exception as e: QMessageBox.critical(self, "Ошибка", f"Не удалось сохранить файл:\n{e}") if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())