QT/PyQT/PySide 通过富文本形式实现关键词高亮

因为本质上都是QT,所以我标题带了QT,这个思路是没问题的,就是用C++得换个语言。

最开始想根据之前一篇博客的思路进行高亮

PyQT/PySide 文本浏览器跳转到指定行,并高亮指定行_qt 指定行高亮_Toblerone_Wind的博客-CSDN博客icon-default.png?t=N4P3https://blog.csdn.net/qq_42276781/article/details/127093403突然想到,QT中的文本浏览器可以设置成HTML的富文本格式,可以解析HTML语法,从而实现关键词高亮。例如,在HTML中,如果想让一个词apple变成红色,只需将原文本由apple替换为

<font color="red">apple</font>

<div style="color:red">apple</div>

这里在文本格式化类中实现了一个高亮函数,来高亮指定的关键词

import html
import re

class TextFormatter():
    __replacement = r'<font color="red">\1</font>' # 替换后保留原单词的大小写
    __keywords = ['TODO','FIXME','HACK','XXX','WORKAROUND']

    def highlight_keywords(self, text:str) -> str:
        # 转义特定字符,防止HTML误解析
        text = html.escape(text) 
        for keyword in self.__keywords:
            # 匹配时不考虑大小写,如需考虑移除re.IGNORECASE即可
            pattern = re.compile(f'({re.escape(keyword)})', re.IGNORECASE) 
            text = pattern.sub(self.__replacement, text)
        return text.strip()

highlight_keywords 函数内部,我们首先使用 html.escape 对文本进行转义,以确保字符的兼容性。然后,针对每个关键词,我们使用正则表达式进行替换操作,将匹配到的关键词用 <font color="red">关键词</font> 标签包裹起来以实现高亮效果。

使用正则表达式模式 re.compile(f'({re.escape(keyword)})', re.IGNORECASE) 来匹配指定单词,并且在替换时通过\1 保留原单词的大小写。

re.escape(keyword) 用于转义特殊字符,re.IGNORECASE 参数用于忽略大小写。然后,使用 pattern.sub(self.__replacement, text) 进行替换操作,将匹配到的关键词替换为 <font color="red">关键词</font> 。

完整代码

from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from sys import argv
import html
import re

class TextFormatter():
    __replacement = r'<font color="red">\1</font>' # 替换后保留原单词的大小写
    __keywords = ['TODO','FIXME','HACK','XXX','WORKAROUND']

    def highlight_keywords(self, text:str) -> str:
        # 转义特定字符,防止HTML误解析
        text = html.escape(text) 
        for keyword in self.__keywords:
            # 匹配时不考虑大小写,如需考虑移除re.IGNORECASE即可
            pattern = re.compile(f'({re.escape(keyword)})', re.IGNORECASE) 
            text = pattern.sub(self.__replacement, text)
        return text.strip()


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(300, 250)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.formLayout = QFormLayout(self.centralwidget)
        self.formLayout.setObjectName(u"formLayout")
        self.textBrowser = QTextBrowser(self.centralwidget)
        self.textBrowser.setObjectName(u"textBrowser")
        self.textBrowser.setLineWrapMode(QTextEdit.NoWrap)
        self.textBrowser.setReadOnly(False)
        font = QFont()
        font.setFamily(u"Arial")
        font.setPointSize(22)
        self.textBrowser.setFont(font)
        self.textBrowser.setHtml(u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'Consolas'; font-size:20pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>")
        self.formLayout.setWidget(0, QFormLayout.SpanningRole, self.textBrowser)
        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi
 
    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))

        text = 'TODO is a food todo'                        # 文本
        text = TextFormatter().highlight_keywords(text)     # 高亮关键词
        self.textBrowser.setText(text)                      # 导入textBrowser
    # retranslateUi
 
 
if __name__ == "__main__":
    app = QApplication(argv)   # 创建应用程序
    mainWindow = QMainWindow() # 创建窗口
    ui = Ui_MainWindow()
    ui.setupUi(mainWindow)
    mainWindow.show()          # 显示窗口
    exit(app.exec_())          # 运行程序直到关闭

效果,文本是TODO is a food todo,高亮显示时不改变原单词的大小写

猜你喜欢

转载自blog.csdn.net/qq_42276781/article/details/130997616
今日推荐