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