Python實(shí)現(xiàn)Markdown格式消除工具
01 引言
在日常使用 Markdown 編寫文檔時(shí),我們有時(shí)會需要將 Markdown 格式的文本轉(zhuǎn)換為純文本,去除其中的各種標(biāo)記符號,如標(biāo)題符號、列表符號、代碼塊標(biāo)記等。手動(dòng)去除這些標(biāo)記不僅效率低下,還容易出錯(cuò)。本文將介紹如何使用 Python 和 PyQt5 庫來創(chuàng)建一個(gè)簡單易用的 Markdown 格式消除工具,并且支持實(shí)時(shí)預(yù)覽和文件保存功能。
02 環(huán)境準(zhǔn)備
在開始之前,我們需要安裝一些必要的庫。主要用到的是 PyQt5 用于創(chuàng)建圖形用戶界面(GUI),以及 Python 內(nèi)置的 re 庫用于正則表達(dá)式匹配,用于去除 Markdown 格式??梢允褂靡韵旅顏戆惭b PyQt5:
pip install PyQt5
03 實(shí)現(xiàn)思路
我們的 Markdown 格式消除工具主要包含以下幾個(gè)部分:
圖形用戶界面(GUI):使用 PyQt5 創(chuàng)建一個(gè)窗口,包含輸入框、輸出框和一些操作按鈕,如導(dǎo)入文本、清除格式、復(fù)制文本、保存文本等。
Markdown 格式處理:使用正則表達(dá)式匹配 Markdown 標(biāo)記符號,并將其替換為空字符串,從而實(shí)現(xiàn)格式消除。
實(shí)時(shí)預(yù)覽:當(dāng)用戶在輸入框中輸入或修改 Markdown 文本時(shí),實(shí)時(shí)更新輸出框中的純文本內(nèi)容。
文件操作:支持直接拖入或?qū)?Markdown 文件和保存處理后的純文本文件。
04 完整代碼
import sys import re from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QTextEdit, QPushButton, QLabel, QFileDialog, QHBoxLayout ) from PyQt5.QtGui import QFont, QClipboard from PyQt5.QtCore import Qt, pyqtSlot class MarkdownRemoverApp(QWidget): def __init__(self): super().__init__() self.dark_theme = False # 初始為亮色主題 self.setAcceptDrops(True) # 啟用拖放功能 self.init_ui() def init_ui(self): """初始化界面""" # 設(shè)置窗口標(biāo)題和大小 self.setWindowTitle("Markdown 格式清除工具") self.setGeometry(100, 100, 800, 800) # 設(shè)置全局字體 font = QFont("Arial", 12) self.setFont(font) # 整體水平布局 main_h_layout = QHBoxLayout() # 左側(cè)文本編輯區(qū)域垂直布局 left_v_layout = QVBoxLayout() # 原始 Markdown 文本部分 self.left_label = QLabel("原始 Markdown 文本") self.left_label.setStyleSheet("font-size: 14px; font-weight: bold;") self.left_text_edit = QTextEdit() self.left_text_edit.setStyleSheet("background-color: #f9f9f9; border: 1px solid #ccc; padding: 10px;") left_v_layout.addWidget(self.left_label) left_v_layout.addWidget(self.left_text_edit) # 清除 Markdown 后的文本部分 self.right_label = QLabel("清除 Markdown 后的文本") self.right_label.setStyleSheet("font-size: 14px; font-weight: bold;") self.right_text_edit = QTextEdit() self.right_text_edit.setStyleSheet("background-color: #f9f9f9; border: 1px solid #ccc; padding: 10px;") left_v_layout.addWidget(self.right_label) left_v_layout.addWidget(self.right_text_edit) # 右側(cè)按鈕垂直布局 right_v_layout = QVBoxLayout() # 導(dǎo)入文本按鈕 self.import_button = QPushButton("導(dǎo)入文本") self.import_button.setStyleSheet(""" QPushButton { background-color: #4CAF50; color: white; font-family: Arial; font-size: 14px; font-weight: bold; padding: 12px 20px; border-radius: 8px; border: none; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } QPushButton:hover { background-color: #66BB6A; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); } QPushButton:pressed { background-color: #388E3C; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transform: translateY(2px); } """) self.import_button.setCursor(Qt.PointingHandCursor) self.import_button.clicked.connect(self.import_text) # 一鍵復(fù)制按鈕 self.copy_button = QPushButton("一鍵復(fù)制") self.copy_button.setStyleSheet(""" QPushButton { background-color: #FF9800; color: white; font-family: Arial; font-size: 14px; font-weight: bold; padding: 12px 20px; border-radius: 8px; border: none; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } QPushButton:hover { background-color: #FFB74D; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); } QPushButton:pressed { background-color: #F57C00; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transform: translateY(2px); } """) self.copy_button.setCursor(Qt.PointingHandCursor) self.copy_button.clicked.connect(self.copy_text) # 一鍵清除按鈕 self.clear_all_button = QPushButton("一鍵清除") self.clear_all_button.setStyleSheet(""" QPushButton { background-color: #F44336; color: white; font-family: Arial; font-size: 14px; font-weight: bold; padding: 12px 20px; border-radius: 8px; border: none; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } QPushButton:hover { background-color: #EF5350; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); } QPushButton:pressed { background-color: #D32F2F; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transform: translateY(2px); } """) self.clear_all_button.setCursor(Qt.PointingHandCursor) self.clear_all_button.clicked.connect(self.clear_all_text) # 主題切換按鈕 self.theme_button = QPushButton("切換主題") self.theme_button.setStyleSheet(""" QPushButton { background-color: #607D8B; color: white; font-family: Arial; font-size: 14px; font-weight: bold; padding: 12px 20px; border-radius: 8px; border: none; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } QPushButton:hover { background-color: #78909C; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); } QPushButton:pressed { background-color: #546E7A; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transform: translateY(2px); } """) self.theme_button.setCursor(Qt.PointingHandCursor) self.theme_button.clicked.connect(self.toggle_theme) # 保存處理后文本按鈕 self.save_button = QPushButton("保存處理后的文本") self.save_button.setStyleSheet(""" QPushButton { background-color: #9E9E9E; color: white; font-family: Arial; font-size: 14px; font-weight: bold; padding: 12px 20px; border-radius: 8px; border: none; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } QPushButton:hover { background-color: #BDBDBD; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); } QPushButton:pressed { background-color: #757575; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transform: translateY(2px); } """) self.save_button.setCursor(Qt.PointingHandCursor) self.save_button.clicked.connect(self.save_text) # 將按鈕添加到右側(cè)按鈕布局 right_v_layout.addWidget(self.import_button) right_v_layout.addWidget(self.copy_button) right_v_layout.addWidget(self.clear_all_button) right_v_layout.addWidget(self.theme_button) right_v_layout.addWidget(self.save_button) # 將左側(cè)文本編輯區(qū)域布局和右側(cè)按鈕布局添加到整體水平布局 main_h_layout.addLayout(left_v_layout) main_h_layout.addLayout(right_v_layout) # 設(shè)置主布局 self.setLayout(main_h_layout) # 連接文本改變信號實(shí)現(xiàn)實(shí)時(shí)預(yù)覽 self.left_text_edit.textChanged.connect(self.update_preview) @pyqtSlot() def update_preview(self): """實(shí)時(shí)更新清除 Markdown 格式后的文本預(yù)覽""" markdown_text = self.left_text_edit.toPlainText() cleaned_text = self._remove_markdown(markdown_text) self.right_text_edit.setPlainText(cleaned_text) def import_text(self): """導(dǎo)入文本文件""" # 打開文件選擇對話框 file_path, _ = QFileDialog.getOpenFileName( self, "選擇文本文件", "", "文本文件 (*.txt);;所有文件 (*)" ) if file_path: # 讀取文件內(nèi)容 try: with open(file_path, "r", encoding="utf-8") as file: content = file.read() # 將內(nèi)容加載到左側(cè)文本框 self.left_text_edit.setPlainText(content) except Exception as e: print(f"讀取文件出錯(cuò): {e}") def copy_text(self): """將清除 Markdown 格式后的文本復(fù)制到剪貼板""" clipboard = QApplication.clipboard() cleaned_text = self.right_text_edit.toPlainText() clipboard.setText(cleaned_text) def clear_all_text(self): """一鍵清除左右文本框的內(nèi)容""" self.left_text_edit.clear() self.right_text_edit.clear() def _remove_markdown(self, text): """ 移除 Markdown 格式并返回純文本 """ # 轉(zhuǎn)換轉(zhuǎn)義字符 text = re.sub(r'\\([\\`*{}[\]()\#+\-.!_>~|])', r'\1', text) # 刪除代碼塊(多行) text = re.sub(r'```[\s\S]*?```', '', text) # 刪除行內(nèi)代碼 text = re.sub(r'`([^`]+)`', r'\1', text) # 處理圖片和鏈接 text = re.sub(r'!\[(.*?)\]\([^)]*\)', r'\1', text) # 圖片 text = re.sub(r'\[(.*?)\]\([^)]*\)', r'\1', text) # 鏈接 # 處理粗體/斜體 text = re.sub(r'\*\*(\*?[\s\S]+?)\*\*', r'\1', text) # **bold** text = re.sub(r'__([\s\S]+?)__', r'\1', text) # __underline__ text = re.sub(r'\*([\s\S]+?)\*', r'\1', text) # *italic* text = re.sub(r'_([\s\S]+?)_', r'\1', text) # _italic_ # 清除標(biāo)題符號 text = re.sub(r'^#+\s*', '', text, flags=re.MULTILINE) # 清除列表符號(支持多級列表) text = re.sub(r'^([\s]*[-*+]|\d+\.)\s+', '', text, flags=re.MULTILINE) # 清除引用塊符號 text = re.sub(r'^>\s*', '', text, flags=re.MULTILINE) # 清除分隔線 text = re.sub(r'^[-*_]{3,}\s*$', '', text, flags=re.MULTILINE) # 合并多余空行并去除首尾空白 text = re.sub(r'\n{3,}', '\n\n', text) return text.strip() def toggle_theme(self): if self.dark_theme: # 切換到亮色主題 self.setStyleSheet("") self.left_text_edit.setStyleSheet("background-color: #f9f9f9; border: 1px solid #ccc; padding: 10px;") self.right_text_edit.setStyleSheet("background-color: #f9f9f9; border: 1px solid #ccc; padding: 10px;") self.left_label.setStyleSheet("font-size: 14px; font-weight: bold;") self.right_label.setStyleSheet("font-size: 14px; font-weight: bold;") self.dark_theme = False else: # 切換到暗色主題 self.setStyleSheet("background-color: #212121; color: white;") self.left_text_edit.setStyleSheet("background-color: #424242; border: 1px solid #616161; padding: 10px; color: white;") self.right_text_edit.setStyleSheet("background-color: #424242; border: 1px solid #616161; padding: 10px; color: white;") self.left_label.setStyleSheet("font-size: 14px; font-weight: bold; color: white;") self.right_label.setStyleSheet("font-size: 14px; font-weight: bold; color: white;") self.dark_theme = True def save_text(self): """保存處理后的文本到指定文件""" file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "文本文件 (*.txt)") if file_path: try: text = self.right_text_edit.toPlainText() with open(file_path, 'w', encoding='utf-8') as file: file.write(text) except Exception as e: print(f"保存文件出錯(cuò): {e}") def dragEnterEvent(self, event): """處理拖入事件,檢查是否是文件""" if event.mimeData().hasUrls(): for url in event.mimeData().urls(): if url.toLocalFile().endswith(('.txt', '.md')): event.acceptProposedAction() return event.ignore() def dropEvent(self, event): """處理放下事件,讀取文件內(nèi)容并加載到左側(cè)文本框""" for url in event.mimeData().urls(): file_path = url.toLocalFile() if file_path.endswith(('.txt', '.md')): try: with open(file_path, 'r', encoding='utf-8') as file: content = file.read() self.left_text_edit.setPlainText(content) except Exception as e: print(f"讀取文件出錯(cuò): {e}") # 主程序入口 if __name__ == "__main__": app = QApplication(sys.argv) window = MarkdownRemoverApp() window.show() sys.exit(app.exec_())
05 運(yùn)行結(jié)果
到此這篇關(guān)于Python實(shí)現(xiàn)Markdown格式消除工具的文章就介紹到這了,更多相關(guān)Python Markdown格式消除內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python中elasticsearch_dsl模塊的使用方法
這篇文章主要介紹了python中elasticsearch_dsl模塊的使用方法,elasticsearch-dsl是基于elasticsearch-py封裝實(shí)現(xiàn)的,提供了更簡便的操作elasticsearch的方法2022-09-09python將十六進(jìn)制值轉(zhuǎn)換為字符串的三種方法
這篇文章主要給大家介紹了關(guān)于python將十六進(jìn)制值轉(zhuǎn)換為字符串的三種方法,工作內(nèi)容的需要需求,經(jīng)常需要使用到字符同16進(jìn)制,以及各個(gè)進(jìn)制之間的轉(zhuǎn)換,需要的朋友可以參考下2023-07-07Python3.x爬蟲下載網(wǎng)頁圖片的實(shí)例講解
今天小編就為大家分享一篇Python3.x爬蟲下載網(wǎng)頁圖片的實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05python使用WMI檢測windows系統(tǒng)信息、硬盤信息、網(wǎng)卡信息的方法
這篇文章主要介紹了python使用WMI檢測windows系統(tǒng)信息、硬盤信息、網(wǎng)卡信息的方法,涉及Python針對系統(tǒng)信息的相關(guān)操作技巧,需要的朋友可以參考下2015-05-05數(shù)組保存為txt, npy, csv 文件, 數(shù)組遍歷enumerate的方法
今天小編就為大家分享一篇數(shù)組保存為txt, npy, csv 文件, 數(shù)組遍歷enumerate的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07Python語法學(xué)習(xí)之正則表達(dá)式的使用詳解
要想成功的進(jìn)行字符串的匹配需要使用到正則表達(dá)式模塊,正則表達(dá)式匹配規(guī)則以及需要被匹配的字符串。本文詳細(xì)為大家介紹了如何利用正則表達(dá)式實(shí)現(xiàn)字符的匹配,感興趣的可以了解一下2022-04-04python實(shí)現(xiàn)比較文件內(nèi)容異同
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)比較文件內(nèi)容異同,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06