如何用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
相关产品推荐
相关产品推荐

