import tkinter as tk from tkinter import scrolledtext, messagebox, filedialog import re class TokenManager: def __init__(self, root): self.root = root self.root.title("C++ Tokenizer Manager (Pro)") self.root.geometry("1000x900") self.root.configure(bg="#f5f5f5") self.tokens = [] # --- Секция 1: Ввод и Загрузка --- top_frame = tk.Frame(root, bg="#f5f5f5") top_frame.pack(fill=tk.X, padx=15, pady=10) tk.Label(top_frame, text="1. Управление токенами:", font=('Arial', 10, 'bold'), bg="#f5f5f5").pack(side=tk.LEFT) btn_load_file = tk.Button(top_frame, text="📥 Загрузить и разбить датасет (.txt)", command=self.load_dataset_file, bg="#FF9800", fg="white", font=('Arial', 9, 'bold')) btn_load_file.pack(side=tk.RIGHT, padx=5) self.input_area = scrolledtext.ScrolledText(root, height=6, font=('Consolas', 10)) self.input_area.pack(padx=15, pady=5, fill=tk.X) self.input_area.insert(tk.END, "// Вставьте старый код конструктора сюда или используйте кнопку загрузки файла...") btn_parse = tk.Button(root, text="Извлечь токены из кода выше", command=self.parse_input, bg="#2196F3", fg="white") btn_parse.pack(pady=5) # --- Секция 2: Средняя часть (Добавление и Список) --- middle_frame = tk.Frame(root, bg="#f5f5f5") middle_frame.pack(padx=15, pady=10, fill=tk.BOTH, expand=True) # Левая колонка: Добавление left_col = tk.LabelFrame(middle_frame, text="Добавить вручную", padx=10, pady=10) left_col.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10)) self.new_token_entry = tk.Entry(left_col, font=('Arial', 11)) self.new_token_entry.pack(fill=tk.X, pady=5) self.new_token_entry.bind('', lambda e: self.add_single_token()) tk.Button(left_col, text="Добавить в список", command=self.add_single_token, bg="#4CAF50", fg="white").pack(fill=tk.X, pady=5) # Правая колонка: Просмотр self.right_col = tk.LabelFrame(middle_frame, text="Текущий список (0 токенов)", padx=10, pady=10) self.right_col.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) list_scroll = tk.Scrollbar(self.right_col) list_scroll.pack(side=tk.RIGHT, fill=tk.Y) self.token_listbox = tk.Listbox(self.right_col, font=('Arial', 10), yscrollcommand=list_scroll.set, selectmode=tk.EXTENDED) self.token_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) list_scroll.config(command=self.token_listbox.yview) tk.Button(self.right_col, text="Удалить выбранные", command=self.delete_selected, bg="#F44336", fg="white").pack(fill=tk.X, pady=(5,0)) # --- Секция 3: Вывод результата --- tk.Label(root, text="3. Готовый код для C++ (token.cpp):", font=('Arial', 10, 'bold'), bg="#f5f5f5").pack(pady=(10,0)) self.output_area = scrolledtext.ScrolledText(root, height=15, bg="#fafafa", font=('Consolas', 10), fg="#2e7d32") self.output_area.pack(padx=15, pady=5, fill=tk.X) # Нижняя панель bottom_frame = tk.Frame(root, bg="#f5f5f5") bottom_frame.pack(fill=tk.X, padx=15, pady=10) self.status_label = tk.Label(bottom_frame, text="Количество токенов: 0", font=('Arial', 11, 'bold'), bg="#f5f5f5") self.status_label.pack(side=tk.LEFT) tk.Button(bottom_frame, text="📋 Копировать код", command=self.copy_to_clipboard, bg="#9E9E9E", fg="white", font=('Arial', 10, 'bold')).pack(side=tk.RIGHT) def load_dataset_file(self): """Открывает файл и разбивает его на токены согласно правилам""" file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt"), ("All files", "*.*")]) if not file_path: return try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() # РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ: # [a-zA-Zа-яА-Я0-9ёЁ-]+ --> Слова (включая цифры и дефисы внутри типа "что-то") # [^\w\s] --> Любой символ, который не буква и не пробел (знаки препинания) pattern = r"[a-zA-Zа-яА-Я0-9ёЁ-]+|[^\w\s]" raw_tokens = re.findall(pattern, content) new_count = 0 for t in raw_tokens: if t not in self.tokens: self.tokens.append(t) new_count += 1 self.refresh_ui() messagebox.showinfo("Загрузка завершена", f"Всего токенов найдено: {len(raw_tokens)}\nДобавлено новых уникальных: {new_count}") except Exception as e: messagebox.showerror("Ошибка", f"Не удалось прочитать файл:\n{str(e)}") def parse_input(self): text = self.input_area.get("1.0", tk.END) found = re.findall(r'add\("(.*?)"\);', text) if not found: messagebox.showwarning("Внимание", "Используйте формат add(\"слово\");") return added = 0 for t in found: if t not in self.tokens: self.tokens.append(t) added += 1 self.refresh_ui() def add_single_token(self): raw_input = self.new_token_entry.get().strip() if not raw_input: return if raw_input not in self.tokens: self.tokens.append(raw_input) self.refresh_ui() self.new_token_entry.delete(0, tk.END) def delete_selected(self): indices = self.token_listbox.curselection() to_remove = [self.token_listbox.get(i) for i in indices] for val in to_remove: self.tokens.remove(val) self.refresh_ui() def refresh_ui(self): self.token_listbox.delete(0, tk.END) for t in self.tokens: self.token_listbox.insert(tk.END, t) self.right_col.config(text=f"Текущий список ({len(self.tokens)} токенов)") self.output_area.delete("1.0", tk.END) code = "Tokenizer() {\n" # Группируем по 6 для красоты в C++ for i in range(0, len(self.tokens), 6): line = self.tokens[i:i+6] code += " " + " ".join([f'add("{t}");' for t in line]) + "\n" code += " }" self.output_area.insert(tk.END, code) self.status_label.config(text=f"Количество токенов: {len(self.tokens)}") def copy_to_clipboard(self): self.root.clipboard_clear() self.root.clipboard_append(self.output_area.get("1.0", tk.END)) messagebox.showinfo("ОК", "Код скопирован") if __name__ == "__main__": root = tk.Tk() app = TokenManager(root) root.mainloop()