Python实现Markdown格式消除工具

 更新时间:2025年02月12日 09:39:13   作者:py小王子  
这篇文章主要为大家详细介绍了如何使用 Python 和 PyQt5 库来创建一个简单易用的 Markdown 格式消除工具,并且支持实时预览和文件保存功能,需要的可以了解下

01 引言 

在日常使用 Markdown 编写文档时,我们有时会需要将 Markdown 格式的文本转换为纯文本,去除其中的各种标记符号,如标题符号、列表符号、代码块标记等。手动去除这些标记不仅效率低下,还容易出错。本文将介绍如何使用 Python 和 PyQt5 库来创建一个简单易用的 Markdown 格式消除工具,并且支持实时预览和文件保存功能。 

02 环境准备 

在开始之前,我们需要安装一些必要的库。主要用到的是 PyQt5 用于创建图形用户界面(GUI),以及 Python 内置的 re 库用于正则表达式匹配,用于去除 Markdown 格式。可以使用以下命令来安装 PyQt5:

pip install PyQt5

03 实现思路

我们的 Markdown 格式消除工具主要包含以下几个部分:

图形用户界面(GUI):使用 PyQt5 创建一个窗口,包含输入框、输出框和一些操作按钮,如导入文本、清除格式、复制文本、保存文本等。

Markdown 格式处理:使用正则表达式匹配 Markdown 标记符号,并将其替换为空字符串,从而实现格式消除。

实时预览:当用户在输入框中输入或修改 Markdown 文本时,实时更新输出框中的纯文本内容。

文件操作:支持直接拖入或导入 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):
        """初始化界面"""
        # 设置窗口标题和大小
        self.setWindowTitle("Markdown 格式清除工具")
        self.setGeometry(100, 100, 800, 800)
 
        # 设置全局字体
        font = QFont("Arial", 12)
        self.setFont(font)
 
        # 整体水平布局
        main_h_layout = QHBoxLayout()
 
        # 左侧文本编辑区域垂直布局
        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)
 
        # 右侧按钮垂直布局
        right_v_layout = QVBoxLayout()
 
        # 导入文本按钮
        self.import_button = QPushButton("导入文本")
        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)
 
        # 一键复制按钮
        self.copy_button = QPushButton("一键复制")
        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)
 
        # 将按钮添加到右侧按钮布局
        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)
 
        # 将左侧文本编辑区域布局和右侧按钮布局添加到整体水平布局
        main_h_layout.addLayout(left_v_layout)
        main_h_layout.addLayout(right_v_layout)
 
        # 设置主布局
        self.setLayout(main_h_layout)
 
        # 连接文本改变信号实现实时预览
        self.left_text_edit.textChanged.connect(self.update_preview)
 
    @pyqtSlot()
    def update_preview(self):
        """实时更新清除 Markdown 格式后的文本预览"""
        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):
        """导入文本文件"""
        # 打开文件选择对话框
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择文本文件", "", "文本文件 (*.txt);;所有文件 (*)"
        )
 
        if file_path:
            # 读取文件内容
            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"读取文件出错: {e}")
 
    def copy_text(self):
        """将清除 Markdown 格式后的文本复制到剪贴板"""
        clipboard = QApplication.clipboard()
        cleaned_text = self.right_text_edit.toPlainText()
        clipboard.setText(cleaned_text)
 
    def clear_all_text(self):
        """一键清除左右文本框的内容"""
        self.left_text_edit.clear()
        self.right_text_edit.clear()
 
    def _remove_markdown(self, text):
        """
        移除 Markdown 格式并返回纯文本
        """
        # 转换转义字符
        text = re.sub(r'\\([\\`*{}[\]()\#+\-.!_>~|])', r'\1', text)
 
        # 删除代码块(多行)
        text = re.sub(r'```[\s\S]*?```', '', text)
 
        # 删除行内代码
        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_
 
        # 清除标题符号
        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"保存文件出错: {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):
        """处理放下事件,读取文件内容并加载到左侧文本框"""
        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"读取文件出错: {e}")
 
 
# 主程序入口
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MarkdownRemoverApp()
    window.show()
    sys.exit(app.exec_())

05 运行结果 

到此这篇关于Python实现Markdown格式消除工具的文章就介绍到这了,更多相关Python Markdown格式消除内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python中elasticsearch_dsl模块的使用方法

    python中elasticsearch_dsl模块的使用方法

    这篇文章主要介绍了python中elasticsearch_dsl模块的使用方法,elasticsearch-dsl是基于elasticsearch-py封装实现的,提供了更简便的操作elasticsearch的方法
    2022-09-09
  • python将十六进制值转换为字符串的三种方法

    python将十六进制值转换为字符串的三种方法

    这篇文章主要给大家介绍了关于python将十六进制值转换为字符串的三种方法,工作内容的需要需求,经常需要使用到字符同16进制,以及各个进制之间的转换,需要的朋友可以参考下
    2023-07-07
  • pytorch ssim计算详细代码例子

    pytorch ssim计算详细代码例子

    这篇文章主要给大家介绍了关于pytorch ssim计算的相关资料,结构相似性(SSIM)是一种测量两幅图像的相似度的方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • Python3.x爬虫下载网页图片的实例讲解

    Python3.x爬虫下载网页图片的实例讲解

    今天小编就为大家分享一篇Python3.x爬虫下载网页图片的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-05-05
  • python使用WMI检测windows系统信息、硬盘信息、网卡信息的方法

    python使用WMI检测windows系统信息、硬盘信息、网卡信息的方法

    这篇文章主要介绍了python使用WMI检测windows系统信息、硬盘信息、网卡信息的方法,涉及Python针对系统信息的相关操作技巧,需要的朋友可以参考下
    2015-05-05
  • MATLAB中print函数使用示例详解

    MATLAB中print函数使用示例详解

    print函数的功能是打印图窗或保存为特定文件格式,这篇文章主要介绍了MATLAB中print函数使用,需要的朋友可以参考下
    2023-03-03
  • Python对wav文件的重采样实例

    Python对wav文件的重采样实例

    今天小编就为大家分享一篇Python对wav文件的重采样实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • 数组保存为txt, npy, csv 文件, 数组遍历enumerate的方法

    数组保存为txt, npy, csv 文件, 数组遍历enumerate的方法

    今天小编就为大家分享一篇数组保存为txt, npy, csv 文件, 数组遍历enumerate的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • Python语法学习之正则表达式的使用详解

    Python语法学习之正则表达式的使用详解

    要想成功的进行字符串的匹配需要使用到正则表达式模块,正则表达式匹配规则以及需要被匹配的字符串。本文详细为大家介绍了如何利用正则表达式实现字符的匹配,感兴趣的可以了解一下
    2022-04-04
  • python实现比较文件内容异同

    python实现比较文件内容异同

    这篇文章主要为大家详细介绍了python实现比较文件内容异同,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-06-06

最新评论