Rurecoder
< Soft
Rurecoder | |
---|---|
Разработчик(и) | zvezdochiot |
Первый выпуск | ~2018 |
Лицензия | PDM 1.0 |
Сайт | github.com |
Rurecoder - программа для дешифровки текста, на подобие Windows-программы Штирлиц.
Установка
$ git clone https://github.com/zvezdochiot/python-rurecoder #(based https://bitbucket.org/dkuryakin/recoder.git) # cd python-rurecoder # cp -r rurecoder /usr/lib64/python3/site-packages
Использование
Примечание: Чтобы расшифровать текст, скопируйте кракозябры в чистый текстовый файл и сохраните его в UTF-8
В консоли
$ echo "Îñíîâíàÿ Îëèìïèéñêàÿ äåðåâíÿ â" | python3 -m rurecoder Основная Олимпийская деревня в
Декодировка файла с выводом
$ cat '/home/user/enca.txt' Ëþäè â Ãðîóâëåíäå, ìàëåíüêîì (ïî ìåðêàì Êàëèôîðíèè) ãîðîäêå â øåñòüñîò æèòåëåé, âûõîäèëè íà óëèöû, ñòîÿëè ïåðåä ñâîèìè äîìàìè ñ öâåòàìè íà ïîäîêîííèêàõ è ñìîòðåëè, êàê ýòîò ïèðîêóìóëþñ âûðàñòàåò âûøå Ñüåððû-Íåâàäû. ß è ñàìà ñòîÿëà òàì â áëàãîãîâåíèè è óæàñå è ïîíèìàëà áåç âñÿêèõ ñëîâ, ÷òî åñëè íå ïîéäåò äîæäü, òî ñëåäóþùèå ïîæàðû áóäóò åù¸ óæàñíåå, à åñëè äîæäè âñ¸ æå ïîéäóò è îêàæóòñÿ ñëèøêîì îáèëüíûìè, òî ýòî ñîææ¸ííûå ãîðíûå ñêëîíû ñìîåò íàâîäíåíèÿìè. Âñ¸ áûëî áóêâàëüíî íà ãðàíè êàòàñòðîôû. Íî ðÿäîì áûëè öâåòû â ãîðøêàõ, è íåîáîææ¸ííûå ñîñíû, è òðóùèåñÿ î íîãè ñîáàêè, è ðåñòîðàí, îòêðûòûé äëÿ óæèíà; è ÷óâñòâîâàëîñü, ÷òî âñå íà óëèöå âçäûõàþò ñ áëàãîäàðíîñòüþ çà òî, ÷òî âñ¸ ýòî ó íèõ åù¸ åñòü. Õîòÿ áû íåíàäîëãî (Äèàíà Ìàðêóì, Äåñÿòûé îñòðîâ).
$ cat '/home/user/enca.txt' | python3 -m rurecoder Люди в Гроувленде, маленьком (по меркам Калифорнии) городке в шестьсот жителей, выходили на улицы, стояли перед своими домами с цветами на подоконниках и смотрели, как этот пирокумулюс вырастает выше Сьерры-Невады. Я и сама стояла там в благоговении и ужасе и понимала без всяких слов, что если не пойдет дождь, то следующие пожары будут ещё ужаснее, а если дожди всё же пойдут и окажутся слишком обильными, то это сожжённые горные склоны смоет наводнениями. Всё было буквально на грани катастрофы. Но рядом были цветы в горшках, и необожжённые сосны, и трущиеся о ноги собаки, и ресторан, открытый для ужина; и чувствовалось, что все на улице вздыхают с благодарностью за то, что всё это у них ещё есть. Хотя бы ненадолго (Диана Маркум, Десятый остров).
Декодировка в новый файл
$ cat '/home/user/enca.txt' | python3 -m rurecoder > /home/user/decom.txt
GUI
Создайте файл с расширением .py со следующим содержимым и запустите его командой python3 file.py
import tkinter as tk from tkinter import ttk, scrolledtext, messagebox import subprocess import webbrowser class TextWithUndo(scrolledtext.ScrolledText): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.undo_stack = [] self.redo_stack = [] # Горячие клавиши self.bind("<Control-z>", self.undo) self.bind("<Control-y>", self.redo) self.bind("<Control-Shift-Z>", self.redo) self.bind("<Key>", self.add_to_undo_stack) # Контекстное меню self.context_menu = tk.Menu(self, tearoff=0) self.context_menu.add_command(label="Вырезать (Ctrl+X)", command=self.cut_text) self.context_menu.add_command(label="Копировать (Ctrl+C)", command=self.copy_text) self.context_menu.add_command(label="Вставить (Ctrl+V)", command=self.paste_text) self.context_menu.add_command(label="Удалить (Del)", command=self.delete_text) self.context_menu.add_separator() self.context_menu.add_command(label="Выделить все (Ctrl+A)", command=self.select_all) self.context_menu.add_separator() self.context_menu.add_command(label="Отменить (Ctrl+Z)", command=self.undo) self.context_menu.add_command(label="Повторить (Ctrl+Y)", command=self.redo) self.bind("<Button-3>", self.show_context_menu) # Правая кнопка мыши self.bind("<Button-1>", self.hide_context_menu) # Левая кнопка мыши def add_to_undo_stack(self, event): if event.keysym not in ("Control_L", "Control_R", "Shift_L", "Shift_R", "Alt_L", "Alt_R", "Z", "Y"): self.undo_stack.append(self.get("1.0", tk.END)) self.redo_stack.clear() def undo(self, event=None): if len(self.undo_stack) > 0: current = self.get("1.0", tk.END) self.redo_stack.append(current) prev_state = self.undo_stack.pop() self.replace_text(prev_state) return "break" def redo(self, event=None): if len(self.redo_stack) > 0: current = self.get("1.0", tk.END) self.undo_stack.append(current) next_state = self.redo_stack.pop() self.replace_text(next_state) return "break" def replace_text(self, text): self.delete("1.0", tk.END) self.insert("1.0", text[:-1]) # Удаляем последний \n def show_context_menu(self, event): try: self.context_menu.tk_popup(event.x_root, event.y_root) finally: self.context_menu.grab_release() def hide_context_menu(self, event): self.context_menu.unpost() def cut_text(self): self.event_generate("<<Cut>>") def copy_text(self): self.event_generate("<<Copy>>") def paste_text(self): self.event_generate("<<Paste>>") def delete_text(self): self.event_generate("<Delete>") def select_all(self): self.tag_add(tk.SEL, "1.0", tk.END) self.mark_set(tk.INSERT, "1.0") self.see(tk.INSERT) return "break" def process_paragraph(paragraph): try: result = subprocess.run( ['python3', '-m', 'rurecoder'], input=paragraph.encode('utf-8'), capture_output=True, check=True ) return result.stdout.decode('utf-8') except subprocess.CalledProcessError as e: return f"Ошибка при обработке:\n{e.stderr.decode('utf-8')}" def process_text(): input_text = input_textbox.get("1.0", tk.END).strip() if not input_text: messagebox.showwarning("Пустой ввод", "Введите текст для обработки.") return paragraphs = [p.strip() for p in input_text.split('\n') if p.strip()] output_textbox.delete("1.0", tk.END) for idx, paragraph in enumerate(paragraphs, 1): output = process_paragraph(paragraph) if add_numbers_var.get(): result_text = f"Абзац {idx}:\n{output}" else: result_text = output if remove_empty_lines_var.get(): output_textbox.insert(tk.END, f"{result_text}\n") else: output_textbox.insert(tk.END, f"{result_text}\n\n") output_textbox.see(tk.END) def handle_paste(event): try: selected = event.widget.tag_ranges(tk.SEL) if selected: event.widget.delete(tk.SEL_FIRST, tk.SEL_LAST) event.widget.insert(tk.INSERT, event.widget.clipboard_get()) return "break" except tk.TclError: pass def handle_cut(event): if event.widget.tag_ranges(tk.SEL): event.widget.clipboard_clear() event.widget.clipboard_append(event.widget.get(tk.SEL_FIRST, tk.SEL_LAST)) event.widget.delete(tk.SEL_FIRST, tk.SEL_LAST) return "break" def handle_delete(event): if event.widget.tag_ranges(tk.SEL): event.widget.delete(tk.SEL_FIRST, tk.SEL_LAST) return "break" def handle_select_all(event): event.widget.tag_add(tk.SEL, "1.0", tk.END) event.widget.mark_set(tk.INSERT, "1.0") event.widget.see(tk.INSERT) return "break" def open_github(event): webbrowser.open("https://github.com/Text-extend-tools/python-rurecoder") # Создаем главное окно root = tk.Tk() root.title("Rurecoder GUI") root.geometry("1000x600") # Переменные для хранения состояний чекбоксов add_numbers_var = tk.BooleanVar(value=True) remove_empty_lines_var = tk.BooleanVar(value=False) # Создаем вкладки notebook = ttk.Notebook(root) notebook.pack(fill=tk.BOTH, expand=True) # Вкладка "Перекодировать текст" tab_recoder = ttk.Frame(notebook) notebook.add(tab_recoder, text="Перекодировать текст") # Главный контейнер для вкладки перекодировки main_container = ttk.Frame(tab_recoder) main_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # Фрейм для текстовых полей text_frame = ttk.Frame(main_container) text_frame.pack(fill=tk.BOTH, expand=True) # Входное поле с предупреждением input_frame = ttk.LabelFrame(text_frame, text="Ввод") input_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) # Добавляем предупреждение перед полем ввода warning_label = ttk.Label( input_frame, text="Внимание! Каждая строка обрабатывается как отдельный абзац", foreground="red", font=("Arial", 10, "bold") ) warning_label.pack(pady=(0, 5)) # Поле ввода с поддержкой undo/redo и контекстным меню input_textbox = TextWithUndo(input_frame, wrap=tk.WORD, font=("Arial", 12)) input_textbox.pack(fill=tk.BOTH, expand=True) # Выходное поле output_frame = ttk.LabelFrame(text_frame, text="Результат") output_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) output_textbox = TextWithUndo(output_frame, wrap=tk.WORD, font=("Arial", 12), state=tk.NORMAL) output_textbox.pack(fill=tk.BOTH, expand=True) # Привязка обработчиков input_textbox.bind("<<Paste>>", handle_paste) input_textbox.bind("<Control-x>", handle_cut) input_textbox.bind("<Delete>", handle_delete) input_textbox.bind("<Control-a>", handle_select_all) output_textbox.bind("<<Paste>>", handle_paste) output_textbox.bind("<Control-x>", handle_cut) output_textbox.bind("<Delete>", handle_delete) output_textbox.bind("<Control-a>", handle_select_all) # Фрейм для кнопки button_frame = ttk.Frame(main_container) button_frame.pack(fill=tk.X, padx=5, pady=5) process_button = ttk.Button(button_frame, text="Распознать", command=process_text) process_button.pack(fill=tk.X, padx=5, pady=5) # Вкладка "Информация" tab_info = ttk.Frame(notebook) notebook.add(tab_info, text="Информация") # Содержимое вкладки информации info_frame = ttk.Frame(tab_info) info_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) info_text = """Rurecoder GUI - написана Ахламовым Петром с помощью ChatGPT и DeepSeek. 2025 г. Используется Rurecoder от zvezdochiot. - Каждая строчка обрабатывается как отдельный абзац. - В одном абзаце может быть только один вид кодировки. """ info_label = ttk.Label( info_frame, text=info_text, font=("Arial", 11), justify=tk.LEFT, padding=20 ) info_label.pack(fill=tk.BOTH, expand=True) # Фрейм для чекбоксов checkboxes_frame = ttk.Frame(info_frame) checkboxes_frame.pack(pady=10) # Чекбокс для подписи абзацев add_numbers_check = ttk.Checkbutton( checkboxes_frame, text="Подписывать распознанные абзацы", variable=add_numbers_var ) add_numbers_check.pack(anchor=tk.W) # Чекбокс для удаления пустых строк remove_empty_lines_check = ttk.Checkbutton( checkboxes_frame, text="Убрать пустую строку между абзацами", variable=remove_empty_lines_var ) remove_empty_lines_check.pack(anchor=tk.W) # Делаем ссылку кликабельной link_label = ttk.Label( info_frame, text="Открыть GitHub проекта Rurecoder", foreground="blue", cursor="hand2", font=("Arial", 11, "underline") ) link_label.pack(pady=(0, 20)) link_label.bind("<Button-1>", open_github) # Обработчик клика по пустому месту в главном окне def hide_menus(event): input_textbox.context_menu.unpost() output_textbox.context_menu.unpost() root.bind("<Button-1>", hide_menus) root.mainloop()
Дополнительно
Примеры кракозябр для теста
Исходная кодировка | При декодировании воспринято как | Результат | Распознает |
---|---|---|---|
При воспроизведении применяется та же кодировка, что и при создании текста. | Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства. | ||
Windows-1251 | Windows-1252 или ISO 8859-1 |
Øèðîêàÿ ýëåêòðèôèêàöèÿ þæíûõ ãóáåðíèé äàñò ìîùíûé òîë÷îê ïîäú¸ìó ñåëüñêîãî õîçÿéñòâà. | |
KOI8-R | ьХПНЙЮЪ ЩКЕЙРПХТХЙЮЖХЪ ЧФМШУ ЦСАЕПМХИ ДЮЯР ЛНЫМШИ РНКВНЙ ОНДЗ╦ЛС ЯЕКЭЯЙНЦН УНГЪИЯРБЮ. | ||
ISO 8859-5 | иш№юърџ §ыхъђ№шєшърішџ ўцэћѕ уѓсх№эшщ фрёђ ьюљэћщ ђюыїюъ яюфњИьѓ ёхыќёъюую ѕючџщёђтр. | ||
CP 866 | ╪шЁюър ¤ыхъЄЁшЇшърЎш ■цэ√ї уєсхЁэшщ фрёЄ ью∙э√щ Єюыўюъ яюф·╕ьє ёхы№ёъюую їюч щёЄтр. | Теряет "я" | |
КОИ-8|KOI8-R | Windows-1252 или ISO 8859-1 |
ûÉÒÏËÁÑ ÜÌÅËÔÒÉÆÉËÁÃÉÑ ÀÖÎÙÈ ÇÕÂÅÒÎÉÊ ÄÁÓÔ ÍÏÝÎÙÊ ÔÏÌÞÏË ÐÏÄߣÍÕ ÓÅÌØÓËÏÇÏ ÈÏÚÑÊÓÔ×Á. | |
Windows-1251 | ыЙТПЛБС ЬМЕЛФТЙЖЙЛБГЙС АЦОЩИ ЗХВЕТОЙК ДБУФ НПЭОЩК ФПМЮПЛ РПДЯЈНХ УЕМШУЛПЗП ИПЪСКУФЧБ. | ||
ISO 8859-5 | ћЩвЯЫСб мЬХЫдвЩЦЩЫСУЩб РжЮйШ ЧеТХвЮЩЪ ФСгд ЭЯнЮйЪ дЯЬоЯЫ аЯФпЃЭе гХЬигЫЯЧЯ ШЯкбЪгдзС. | ||
CP 866 | √╔╥╧╦┴╤ ▄╠┼╦╘╥╔╞╔╦┴├╔╤ └╓╬┘╚ ╟╒┬┼╥╬╔╩ ─┴╙╘ ═╧▌╬┘╩ ╘╧╠▐╧╦ ╨╧─▀г═╒ ╙┼╠╪╙╦╧╟╧ ╚╧┌╤╩╙╘╫┴. | ||
7 бит | {IROKAQ \LEKTRIFIKACIQ @VNYH GUBERNIJ DAST MO]NYJ TOL^OK POD_#MU SELXSKOGO HOZQJSTWA. | не распознает | |
ISO 8859-5 | Windows-1252 или ISO 8859-1 |
ÈØàÞÚÐï íÛÕÚâàØäØÚÐæØï îÖÝëå ÓãÑÕàÝØÙ ÔÐáâ ÜÞéÝëÙ âÞÛçÞÚ ßÞÔêñÜã áÕÛìáÚÞÓÞ åÞ×ïÙáâÒÐ. | |
Windows-1251 | ИШаЮЪРп нЫХЪваШдШЪРжШп оЦЭле УгСХаЭШЩ ФРбв ЬЮйЭлЩ вЮЫзЮЪ ЯЮФксЬг бХЫмбЪЮУЮ еЮЧпЩбвТР. | ||
КОИ-8/KOI8-R | хьЮчзпО МшузБЮьДьзпФьО НжщКЕ сЦяуЮщьы тпАБ эчИщКы БчшГчз ъчтЙЯэЦ АушЛАзчсч ЕчвОыАБрп. | ||
Альтернативная кодировка/CP 866 | ╚╪р▐┌╨я э█╒┌тр╪ф╪┌╨ц╪я ю╓▌ых ╙у╤╒р▌╪┘ ╘╨ст ▄▐щ▌ы┘ т▐█ч▐┌ ▀▐╘ъё▄у с╒█ьс┌▐╙▐ х▐╫я┘ст╥╨. | ||
Альтернативная кодировка|CP 866 | Windows-1252 | ˜¨à®ª ï í«¥ªâà¨ä¨ª æ¨ï î¦ëå £ã¡¥à¨© ¤ áâ ¬®éë© â®«ç®ª ¯®¤êñ¬ã ᥫì᪮£® å®§ï©á⢠. | Не распознал ш, а, . |
Windows-1251 | �Ёа®Є п н«ҐЄваЁдЁЄ жЁп о¦ле ЈгЎҐаЁ© ¤ бв ¬®йл© в®«з®Є Ї®¤кс¬г ᥫмбЄ®Ј® е®§п©бвў . | Не распознал ш, а | |
КОИ-8 | ≤╗Ю╝╙═О М╚╔╙БЮ╗Д╗╙═Ф╗О Н╕╜КЕ ёЦ║╔Ю╜╗╘ ╓═АБ ╛╝И╜К╘ Б╝╚Г╝╙ ╞╝╓ЙЯ╛Ц А╔╚ЛА╙╝ё╝ Е╝╖О╘АБ╒═. | ||
ISO 8859-5 | �ЈрЎЊ я эЋЅЊтрЈфЈЊ цЈя юІых ЃуЁЅрЈЉ Є ст ЌЎщыЉ тЎЋчЎЊ ЏЎЄъёЌу сЅЋьсЊЎЃЎ хЎЇяЉстЂ . | Не распознал ш, а, . | |
CP437 | ÿ¿α«¬á∩ φ½Ñ¬Γα¿Σ¿¬áµ¿∩ δσ úπíÑα¡¿⌐ ñáßΓ ¼«Θ¡δ⌐ Γ«½τ«¬ »«ñΩ±¼π ßѽ∞߬«ú« σ«º∩⌐ßΓóá. | ||
UTF-8 | Windows-1252 | Ð¨Ð¸Ñ€Ð¾ÐºÐ°Ñ ÑÐ»ÐµÐºÑ‚Ñ€Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ ÑŽÐ¶Ð½Ñ‹Ñ… губерний даÑÑ‚ мощный толчок подъёму ÑельÑкого хозÑйÑтва. | Не распознал а, э, с |
Windows-1251 | Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства. | ||
КОИ-8 | п╗п╦я─п╬п╨п╟я▐ я█п╩п╣п╨я┌я─п╦я└п╦п╨п╟я├п╦я▐ я▌п╤п╫я▀я┘ пЁя┐п╠п╣я─п╫п╦п╧ п╢п╟я│я┌ п╪п╬я┴п╫я▀п╧ я┌п╬п╩я┤п╬п╨ п©п╬п╢я┼я▒п╪я┐ я│п╣п╩я▄я│п╨п╬пЁп╬ я┘п╬п╥я▐п╧я│я┌п╡п╟. | ||
ISO 8859-5 | аЈаИб�аОаКаАб� б�аЛаЕаКб�б�аИб�аИаКаАб�аИб� б�аЖаНб�б� аГб�аБаЕб�аНаИаЙ аДаАб�б� аМаОб�аНб�аЙ б�аОаЛб�аОаК аПаОаДб�б�аМб� б�аЕаЛб�б�аКаОаГаО б�аОаЗб�аЙб�б�аВаА. | Криво распознал | |
CP 866 | ╨и╨╕╤А╨╛╨║╨░╤П ╤Н╨╗╨╡╨║╤В╤А╨╕╤Д╨╕╨║╨░╤Ж╨╕╤П ╤О╨╢╨╜╤Л╤Е ╨│╤Г╨▒╨╡╤А╨╜╨╕╨╣ ╨┤╨░╤Б╤В ╨╝╨╛╤Й╨╜╤Л╨╣ ╤В╨╛╨╗╤З╨╛╨║ ╨┐╨╛╨┤╤К╤С╨╝╤Г ╤Б╨╡╨╗╤М╤Б╨║╨╛╨│╨╛ ╤Е╨╛╨╖╤П╨╣╤Б╤В╨▓╨░. | ||
UTF-16 | CP 866 | (♦8♦@♦>♦:♦0♦O♦ M♦;♦5♦:♦B♦@♦8♦D♦8♦:♦0♦F♦8♦O♦ N♦6♦=♦K♦E♦ 3♦C♦1♦5♦@♦=♦8♦9♦ 4♦0♦A♦B♦ <♦>♦I♦=♦K♦9♦ B♦>♦;♦G♦>♦:♦ ?♦>♦4♦J♦Q♦<♦C♦ A♦5♦;♦L♦A♦:♦>♦3♦>♦ E♦>♦7♦O♦9♦A♦B♦2♦0♦. | Криво распознал |