You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用QTextCursor高效选中文本?存在性能瓶颈

优化PyQt6文本块开头时间戳替换的性能问题

我需要替换文档每个块开头的时间戳,现有PoC代码功能正常但运行卡顿。问题应该出在通过搜索定位文本上——我明确知道目标文本在块的开头,但不知道怎么直接选中它。

初始代码(功能正常但卡顿)

from PyQt6 import QtWidgets, QtGui
import time


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        # 创建纯文本编辑控件并添加测试文本
        self.text_edit = QtWidgets.QPlainTextEdit()
        text = ''
        for i in range(10000):
            text+="2022 something or the other\n2022 some other test\n"
        self.text_edit.setPlainText(text)
        self.setCentralWidget(self.text_edit)

        # 创建按钮并绑定文本替换函数
        self.button = QtWidgets.QPushButton("修改文本")
        self.button.clicked.connect(self.select_text)
        toolbar = self.addToolBar("工具栏")
        toolbar.addWidget(self.button)

    def select_text(self):
        old = ["2022"] * 20000
        new = ["2023"] * 20000
        start_time = time.perf_counter()
        cursor = self.text_edit.textCursor()
        cursor.beginEditBlock()

        for i in range(self.text_edit.document().blockCount()):
            block = self.text_edit.document().findBlockByNumber(i)
            # 在块内搜索目标字符串
            block_cursor = QtGui.QTextCursor(block)
            while not block_cursor.atEnd() and block_cursor.block() == block:
                # block_cursor.movePosition(QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor, 4)
                block_cursor = block.document().find(old[i], block_cursor)

                if not block_cursor.isNull():
                    block_cursor.insertText(new[i])
        cursor.endEditBlock()
        end_time = time.perf_counter()
        elapsed_time = end_time - start_time
        print(f"耗时: {elapsed_time:.2f} 秒")


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

目前代码可正常工作,但希望用movePosition替代搜索来提升性能。


第一次改进(基于外部建议)

def select_text(self):
        old = ["2022"] * 20000
        new = ["2023"] * 20000
        start_time = time.perf_counter()
        cursor = self.text_edit.textCursor()
        cursor.beginEditBlock()
        i=0
        doc = self.text_edit.document()
        find_cursor = QtGui.QTextCursor(doc.begin())
        while True:
            find_cursor = doc.find(old[i], find_cursor)
            if not find_cursor.isNull():
                find_cursor.insertText(new[i])
                i=i+1
                if i == 20000:
                    break
            else:
                break
        cursor.endEditBlock()
        end_time = time.perf_counter()
        elapsed_time = end_time - start_time
        print("耗时: {:.2f} 秒".format(elapsed_time))

最终需求与代码(时区转换场景)

应用目标是处理时区未知的时间戳,通过添加UTC偏移将其转换为UTC格式。重新设计的示例代码如下:

from PyQt6 import QtWidgets, QtGui
import time
import datetime


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        # 创建纯文本编辑控件并添加测试文本
        self.text_edit = QtWidgets.QPlainTextEdit()
        text = "2022-08-02T15:41:05.000  something or the other\n2022-08-02T15:41:06.000  Some parts may contain timestamps 2021-08-02T15:42:06.000 or\u2028New lines within a block\n2022-08-02T15:42:06.000  some other test"
        self.text_edit.setPlainText(text)
        self.setCentralWidget(self.text_edit)

        # 创建按钮并绑定时区转换函数
        self.button = QtWidgets.QPushButton("修改文本")
        self.button.clicked.connect(self.shift_timezone)
        toolbar = self.addToolBar("工具栏")
        toolbar.addWidget(self.button)

    def shift_timezone(self):
        text_timestamps = [1659447665, 1659447666, 1659447726]
        start_time = time.perf_counter()
        cursor = self.text_edit.textCursor()
        cursor.movePosition(cursor.MoveOperation.Start, cursor.MoveMode.MoveAnchor)
        cursor.beginEditBlock()
        i=0
        while i<self.text_edit.document().blockCount():
            dt = datetime.datetime.fromtimestamp(text_timestamps[i]+3600)
            iso_string = dt.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
            cursor.movePosition(cursor.MoveOperation.Right, cursor.MoveMode.KeepAnchor, 24)
            cursor.insertText(iso_string)
            cursor.movePosition(cursor.MoveOperation.NextBlock, cursor.MoveMode.MoveAnchor)
            i= i+1
        cursor.endEditBlock()
        end_time = time.perf_counter()
        elapsed_time = end_time - start_time
        print(f"耗时: {elapsed_time:.2f} 秒")


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

(我在原始显示文本中特意添加了一个空格作为Zulu时区标识的占位符,以支持多次运行该函数)

这段代码功能完全正常,但性能极差——运行时间是直接重建文档的7倍。由于无法控制内容,文档中可能包含与目标格式相同的时间戳,块内也可能存在换行。

我明确知道所有块均以固定格式的时间戳开头,且可控制时间戳格式,同时在其他变量中存有时间戳和内容的源数据,可直接重建文档。

请问我是不是犯了明显的性能密集型错误?


内容的提问来源于stack exchange,提问作者Balog Dániel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 14:44:56