init
This commit is contained in:
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Build artifacts
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
10163
firstLabVisualProg/Untitled-1.txt
Normal file
10163
firstLabVisualProg/Untitled-1.txt
Normal file
File diff suppressed because it is too large
Load Diff
387
firstLabVisualProg/main.py
Normal file
387
firstLabVisualProg/main.py
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
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_())
|
||||||
44
firstLabVisualProg/main.spec
Normal file
44
firstLabVisualProg/main.spec
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['main.py'],
|
||||||
|
pathex=[],
|
||||||
|
binaries=[],
|
||||||
|
datas=[],
|
||||||
|
hiddenimports=[],
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.datas,
|
||||||
|
[],
|
||||||
|
name='main',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=False,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
)
|
||||||
|
app = BUNDLE(
|
||||||
|
exe,
|
||||||
|
name='main.app',
|
||||||
|
icon=None,
|
||||||
|
bundle_identifier=None,
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user