[手搓人]大战[高亮编辑器/查找替换/函数跳跳蛙]--巅峰对决(1)
战前准备
github
以及它的访问权限- 强大的心理支撑
- 一点点英文水平(至少会念ABC )
- 会写测试样例
- 面向对象要学好(没学真的会感到是在地狱)
使用环境
python 3.8.0
pyqt 5.15.9
pycharm 2021.3
基础类
基本上在这两个类反复横跳
QsciScintilla
QTextEdit
手册或者参考
QTextEdit
的应用
这是我的小小爹
QsciScintilla
的应用
这是大爹但又没完全是
QTextEdit
跟着github
上的代码走就没问题…
import sys
from PyQt5.QtCore import QRegExp
from PyQt5.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter## 不用QS的...
def format(color, style=''):"""Return a QTextCharFormat with the given attributes."""_color = QColor()if type(color) is not str:_color.setRgb(color[0], color[1], color[2])else:_color.setNamedColor(color)_format = QTextCharFormat()_format.setForeground(_color)if 'bold' in style:_format.setFontWeight(QFont.Bold)if 'italic' in style:_format.setFontItalic(True)return _formatSTYLES = {'header': format([0, 128, 0]), # 头文件'd_header': format([60,179,113]), # 头文件'keyword': format('#2E8B57', 'bold'),'operator': format([255, 140, 0]), # 运算符'brace': format([255, 140, 0]), # 符号'defclass': format([0, 80, 50], 'bold'), # 类名'string': format([132, 26, 138]), # 字符串'string2': format([132, 26, 138]), # 字符串'comment': format([107, 147, 186]), # 注释'self': format([150, 85, 140], 'italic'), # 自身'numbers': format([42, 0, 255]), # 数字'constant': format([202, 0, 202], 'bold'), # 常量'deprecated': format([123, 23, 43], 'bold underline'), # 弃用的成员'enums': format([128, 0, 255]), # 枚举'fields': format([128, 0, 128]), # 变量'return': format([255, 0, 85], 'bold'), # return关键字'method_decl': format([255, 128, 64], 'bold'), # 方法定义'method': format([0, 48, 96]), # 方法'others': format([78, 123, 0]), # 其他'static_fields': format([33, 0, 189], 'bold'), # 静态变量
}class CppHighlighter(QSyntaxHighlighter):"""Syntax highlighter for the C/C++ language."""# headerheader = ['stdio.h', 'stdlib.h', 'math.h', 'string.h', 'time.h', 'ctype.h','stdbool.h', 'assert.h', 'limits.h', 'float.h', 'stddef.h', 'errno.h','signal.h', 'setjmp.h', 'stdarg.h', 'locale.h', 'wchar.h', 'time.h','unistd.h', 'fcntl.h', 'sys/types.h', 'sys/stat.h', 'dirent.h','pthread.h', 'semaphore.h', 'sys/socket.h', 'netinet/in.h','arpa/inet.h', 'netdb.h', 'sys/time.h', 'sys/wait.h']# C/C++ keywordskeywords = ['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do','double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int','long', 'register', 'return', 'short', 'signed', 'sizeof', 'static','struct', 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile','while', 'bool', 'catch', 'class', 'const_cast', 'delete', 'dynamic_cast','explicit', 'false', 'friend', 'inline', 'mutable', 'namespace', 'new','operator', 'private', 'protected', 'public', 'reinterpret_cast','static_cast', 'template', 'this', 'throw', 'true', 'try', 'typeid','typename', 'using', 'virtual', 'wchar_t',]# C/C++ operatorsoperators = ['=',# Comparison'==', '!=', '<', '<=', '>', '>=',# Arithmetic'\+', '-', '\*', '/', '//', '\%', '\*\*',# In-place'\+=', '-=', '\*=', '/=', '\%=',# Bitwise'\^', '\|', '\&', '\~', '>>', '<<',]# C/C++ bracesbraces = ['\{', '\}', '\(', '\)', '\[', '\]',]def __init__(self, document):QSyntaxHighlighter.__init__(self, document)rules = []# Header rules: #include<XX.h>header_rules1 = [('#include\s*<{}>'.format(a), 0, STYLES['header'])for a in CppHighlighter.header]# Header rules: #include "XXX.h"header_rules2 = [(r'#include\s*"([^"]+)"', 0, STYLES['d_header']),]rules += [(r'\b%s\b' % w, 0, STYLES['keyword'])for w in CppHighlighter.keywords]# print(rules)rules += [(r'%s' % o, 0, STYLES['operator'])for o in CppHighlighter.operators]rules += [(r'%s' % b, 0, STYLES['brace'])for b in CppHighlighter.braces]# All other rulesrules += [# 'self'(r'\bself\b', 0, STYLES['self']),# Double-quoted string, possibly containing escape sequences(r'"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),# Single-quoted string, possibly containing escape sequences(r"'[^'\\]*(\\.[^'\\]*)*'", 0, STYLES['string2']),# 'def' followed by an identifier(r'\bdef\b\s*(\w+)', 1, STYLES['defclass']),# 'class' followed by an identifier(r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),# From '#' until a newline(r'#[^\n]*', 0, STYLES['comment']),# Numeric literals(r'\b[+-]?[0-9]+[lL]?\b', 0, STYLES['numbers']),(r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b', 0, STYLES['numbers']),(r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0,STYLES['numbers']),]rules += header_rules1rules += header_rules2self.rules = [(QRegExp(pat), index, fmt)for (pat, index, fmt) in rules]def highlightBlock(self, text):for expression, nth, format in self.rules:index = expression.indexIn(text, 0)while index >= 0:# We actually want the index of the nth matchindex = expression.pos(nth) + expression.cap(nth).index(expression.cap(nth))length = len(expression.cap(nth))self.setFormat(index, length, format)index = expression.indexIn(text, index + length)self.setCurrentBlockState(0)if __name__ == "__main__":from PyQt5 import QtWidgetsapp = QtWidgets.QApplication([])editor = QtWidgets.QPlainTextEdit()editor.setStyleSheet("""QPlainTextEdit{font-family:'Consolas'; background-color: rgb(204,232,207);}""")highlight = CppHighlighter(editor.document())editor.show()# Load sample.cpp into the editor for demo purposesinfile = open('your_file_path', 'r', encoding='utf-8')editor.setPlainText(infile.read())app.exec_()
QsciScintilla
全部重写
你没看错全部重写…
QsciScintilla
类重写动作
class MeQsciScintilla(QsciScintilla):# 继承编辑器类 重写键盘按键方法def __init__(self, parent=None):super(MeQsciScintilla, self).__init__(parent)def keyPressEvent(self, e):''' 测试按下按键 '''if e.key() == Qt.Key_Escape:passsuper().keyPressEvent(e)def wheelEvent(self, e):''' Ctrl + 滚轮 控制字体缩放 '''if e.modifiers() == Qt.ControlModifier:da = e.angleDelta()if da.y() > 0:self.zoomIn(1) # QsciScintilla 自带缩放elif da.y() < 0:self.zoomOut(1)else:super().wheelEvent(e)
LexerCustom
类重写高亮和自动补全
class MeLexer(QsciLexerCustom):def __init__(self, parent):super(MeLexer, self).__init__(parent)# 父类是编辑器# 设置默认颜色# 设置默认背景# 设置默认字号self.setDefaultColor(QColor("#ff000000"))self.setDefaultPaper(QColor("#CCE8CF")) # 背景 豆沙绿self.setDefaultFont(QFont("Consolas", 13))# 样式表 0-1-2-3-4-5# 0: 关键字 1: 运算符 2: 格式符 3: 数字 4: 默认 5: 注释# 颜色self.setColor(QColor("#3CB371"), 0)self.setColor(QColor("#6A5ACD"), 1)self.setColor(QColor("#20B2AA"), 2)self.setColor(QColor("#4169E1"), 3)self.setColor(QColor("#2D7C7F"), 4)self.setColor(QColor("#C0C0C0"), 5)# 字体 consolas DevC++的默认字体 字号自定self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 0)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 1)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 2)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 3)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 4)self.setFont(QFont("Consolas", 13), 5)self.font(5).setItalic(True)# 定义关键词列表self.keywords_list = ['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do','double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int','long', 'register', 'return', 'short', 'signed', 'sizeof', 'static','struct', 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile','while', 'bool', 'catch', 'class', 'const_cast', 'delete', 'dynamic_cast','explicit', 'false', 'friend', 'inline', 'mutable', 'namespace', 'new','operator', 'private', 'protected', 'public', 'reinterpret_cast','static_cast', 'template', 'this', 'throw', 'true', 'try', 'typeid','typename', 'using', 'virtual', 'wchar_t', 'include', 'std',"byte", "word", "dword","int8_t", "uint8_t", "int16_t", "uint16_t","int32_t", "uint32_t", "int64_t", "uint64_t","int8", "uint8", "int16", "uint16","int32", "uint32", "int64", "uint64"]# 定义运算符列表self.operator_list = ['=',# Comparison'==', '!=', '<', '<=', '>', '>=',# Arithmetic'+', '-', '*', '/', '%',# In-place'+=', '-=', '*=', '/=', '%=',# Bitwise'^', '|', '&', '~', '>>', '<<', '"', '%s', '%f', '%d', '%ld']# 定义格式符列表self.format_list = ['{', '}', '(', ')', '[', ']', '#', ';', ',']def description(self, style):if style == 0:return "keyword_style"elif style == 1:return "operate_style"elif style == 2:return "format_style"elif style == 3:return "number_style"elif style == 4:return "default_style"elif style == 5:return "tips_style"### 无需返回值 但需要定义内容return ""def styleText(self, start, end):# 1. 初始化风格类self.startStyling(start)# 2. 切片数据text = self.parent().text()[start:end]# 3. 词法分析p = re.compile(r"\*\/|\/\*|//.*?(?=\r?\n|$)|\s+|\w+|\W") # // and /**/# 关键词列表里是这样的元组 (token_name, token_len) :(关键词内容,关键词长度)token_list = [(token, len(bytearray(token, "utf-8"))) for token in p.findall(text)]# 4. 风格化# 4.1 分支multiline_comm_flag = Falseeditor = self.parent()if start > 0:previous_style_nr = editor.SendScintilla(editor.SCI_GETSTYLEAT, start - 1)if previous_style_nr == 3:multiline_comm_flag = True# 4.2 循环风格化for i, token in enumerate(token_list):if multiline_comm_flag:# 处于块注释状态,使用样式5进行风格化self.setStyling(token[1], 5)if token[0] == "*/":multiline_comm_flag = Falseelif token[0].startswith("//"):line_number = self.parent().SendScintilla(self.parent().SCI_LINEFROMPOSITION, start)line_start = self.parent().SendScintilla(self.parent().SCI_POSITIONFROMLINE, line_number)line_end = self.parent().SendScintilla(self.parent().SCI_GETLINEENDPOSITION, line_number)self.startStyling(line_start)self.setStyling(line_end - line_start + 1, 5)break # 结束循环,不再继续处理该行后面的内容else:# 其他情况根据关键词、运算符、格式符、数字进行风格化if token[0] in self.keywords_list:self.setStyling(token[1], 0)elif token[0] in self.operator_list:self.setStyling(token[1], 1)elif token[0] in self.format_list:self.setStyling(token[1], 2)elif token[0].isdigit():self.setStyling(token[1], 3)elif token[0] == "/*":multiline_comm_flag = Trueself.setStyling(token[1], 5)else:self.setStyling(token[1], 4)
TextEditorWidget
类,重写QWidget
类,隐藏上面两个重写类,并写交互接口
class TextEditorWidget(QWidget):gotoDeclarationSign = QtCore.pyqtSignal()gotoDefinitionSign = QtCore.pyqtSignal()gotoCallExpressSign = QtCore.pyqtSignal()def __init__(self, filename, filepath):super(TextEditorWidget, self).__init__(parent=None)# 配置config_obj = Config()self.config_ini = config_obj.read_config()# 可访问成员变量self.filename = filenameself.filepath = filepathself.status = False# 创建布局self.__layout = QVBoxLayout(self)self.__frame = QFrame(self)self.__frameLayout = QVBoxLayout(self.__frame)self.__layout.addWidget(self.__frame)# 创建编辑器self.__editor = MeQsciScintilla(self.__frame)# 这里设置自定义词法解析器CPPself.__lexer = MeLexer(self.__editor)# 配置MeLexer 里面有自定义的高亮风格self.__editor.setLexer(self.__lexer)# 设置自动补全敏感字数self.__editor.setAutoCompletionThreshold(1)self.__editor.setAutoCompletionSource(QsciScintilla.AcsAll)# 设置自动补全对象self.__api = QsciAPIs(self.__lexer)# 设置自动补全敏感self.__editor.setAutoCompletionCaseSensitivity(True)# 设置自动补全替换self.__editor.setAutoCompletionReplaceWord(True)# 设置自动填充self.__editor.setAutoCompletionFillupsEnabled(True)# 显示全部调用 不受上下文限制self.__editor.setCallTipsStyle(QsciScintilla.CallTipsNoContext)# 自动补全选项在下面self.__editor.setCallTipsPosition(QsciScintilla.CallTipsBelowText)self.__editor.setCallTipsVisible(0)# 菜单# 设置默认菜单为自定义菜单self.__editor.setContextMenuPolicy(Qt.CustomContextMenu)# 设置触发self.__editor.customContextMenuRequested.connect(self.show_context_menu)autocompletions = ['include', 'using', 'namespace', 'std','scanf', 'printf', 'return', 'char', '{}','[]', '()', 'int', 'double', 'long', 'float','string', 'endl', 'stdio.h', 'stdlib.h', 'iostream', '<>','free', 'malloc', 'new', 'delete', 'public', 'private', 'protected','cin', 'cout', 'for', 'while', 'do', 'const', 'continue', 'break', 'if', 'else','auto', 'signed', 'short', 'case', 'try', 'catch', 'switch', 'default','true', 'false', 'struct', 'typedef', 'goto', 'sizeof', 'void', 'static', 'union','enum', 'inline', 'extern', 'throw', 'bool', 'class', 'template', 'this', 'vector','math.h', 'abs', 'strcat', 'strcmp', 'strlen', 'strcpy', 'strchr', 'strstr', 'rand','exit', 'time.h', 'string.h', 'ctype.h', 'isdigit', 'isalpha', 'isblank', 'isalnum','getchar', 'fopen', 'fflush', 'fclose', 'remove', 'fprintf', 'puts', 'abort', 'ctime']for ac in autocompletions:self.__api.add(ac)self.__api.prepare()self.__editor.setCallTipsBackgroundColor(QColor('#D8BFD8'))# 设置自动补全字体颜色self.__editor.setCallTipsForegroundColor(QColor('#F08080'))# utf-8self.__editor.setUtf8(True)# 将编辑器添加到布局中self.__frameLayout.addWidget(self.__editor)# 细节# 设置背景色self.__editor.setPaper(QColor("#CCE8CF"))# 显示自动换行self.__editor.setWrapMode(QsciScintilla.WrapWord)self.__editor.setWrapVisualFlags(QsciScintilla.WrapFlagByText)self.__editor.setWrapIndentMode(QsciScintilla.WrapIndentIndented)# 使用tabself.__editor.setIndentationsUseTabs(True)# 设置换行符长度4self.__editor.setTabWidth(4)# 设置Tab自动对齐self.__editor.setAutoIndent(True)# 设置鼠标光标颜色 前景色...self.__editor.setCaretForegroundColor(QColor("#0000CD"))# 设置选中行颜色self.__editor.setCaretLineVisible(True)self.__editor.setCaretLineBackgroundColor(QColor("#AAEDCB"))# 行号/页边距颜色# 显示行号 行号范围self.__editor.setMarginLineNumbers(1, True)self.__editor.setMarginWidth(1, '0000')self.__editor.setMarginsForegroundColor(QColor("#006400"))# 默认未修改self.__editor.setModified(False)def show_context_menu(self, point):self.context_menu = self.__editor.createStandardContextMenu()# 添加默认选项self.context_menu.insertSeparator(self.context_menu.actions()[0])ui_icon = self.config_ini['main_project']['project_name'] + self.config_ini['ui_img']['ui_turn_to']action_goto_declaration = QAction("转到声明", self)action_goto_declaration.setIcon(QIcon(ui_icon))action_goto_declaration.triggered.connect(self.gotoDeclaration)action_goto_definition = QAction("转到定义", self)action_goto_definition.setIcon(QIcon(ui_icon))action_goto_definition.triggered.connect(self.gotoDefinition)action_goto_call_express = QAction("转到调用", self)action_goto_call_express.setIcon(QIcon(ui_icon))action_goto_call_express.triggered.connect(self.gotoCallExpress)# 分隔符self.context_menu.insertSeparator(self.context_menu.actions()[0])self.context_menu.insertAction(self.context_menu.actions()[0], action_goto_declaration)self.context_menu.insertAction(self.context_menu.actions()[1], action_goto_definition)self.context_menu.insertAction(self.context_menu.actions()[2], action_goto_call_express)# 应用self.context_menu.exec_(self.__editor.mapToGlobal(point))def gotoDeclaration(self):self.gotoDeclarationSign.emit()def gotoDefinition(self):self.gotoDefinitionSign.emit()def gotoCallExpress(self):self.gotoCallExpressSign.emit()def highlight_function_declaration(self, positions):# 传入的是整个位置数据....indicator_number = 1 # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)indicator_color = QColor('#f05b72') # 蔷薇色if positions:self.highlight_handle(positions, lines, indexs, indicator_number, indicator_color)def highlight_function_definition(self, positions):# 传入的是整个位置数据....indicator_number = 2 # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)indicator_color = QColor('#ed1941') # 赤色if positions:self.highlight_handle(positions, lines, indexs, indicator_number, indicator_color)def highlight_function_call_express(self, positions):# 传入的是整个位置数据....indicator_number = 3 # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)indicator_color = QColor('#f47920') # 橙色if positions:self.highlight_handle(positions, lines, indexs, indicator_number, indicator_color)def highlight_handle(self, positions, lines, indexs, indicator_number, indicator_color):self.__editor.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, indicator_number)# 清除所有指示器的色块填充for i in range(1, 4):self.__editor.clearIndicatorRange(0, 0, lines, indexs, i)self.__editor.SendScintilla(QsciScintilla.SCI_INDICATORCLEARRANGE, 0,self.__editor.SendScintilla(QsciScintilla.SCI_GETLINECOUNT))for start_line, start_index, end_line, end_index in positions:self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETSTYLE, indicator_number,QsciScintilla.INDIC_CONTAINER)self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETFORE, indicator_number,indicator_color)self.__editor.fillIndicatorRange(start_line, start_index, end_line, end_index, indicator_number)self.__editor.setCursorPosition(end_line, end_index)# 获取选中位置文本 返回位置和一模一样文本def getSelected_Position_Content(self):if self.__editor.getSelection() != (-1, -1, -1, -1):selected_text = self.__editor.selectedText()start_line = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_LINEFROMPOSITION,self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONSTART)) # 设置起始行号为当前选中文本所在行start_index = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETCOLUMN, self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONSTART)) # 设置起始索引为当前选中文本的起始位置end_line = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_LINEFROMPOSITION, self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONEND)) # 设置结束行号为当前选中文本的结束行end_index = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETCOLUMN, self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONEND)) # 设置结束索引为当前选中文本的结束位置return [(start_line, start_index, end_line, end_index)], selected_textdef getSelectdFunctionName(self, input_string):import repattern = r'\b(\w+)\s*\('match = re.search(pattern, input_string)if match:return match.group(1)words = re.findall(r'\b\w+\b', input_string) # 提取字符串中的单词列表for word in words:if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', word): # 判断单词是否符合函数名的命名规则return word # 返回第一个符合要求的单词作为函数名return None# 这里是添加内容def addText(self, content):# 防止有憨憨放列表进来...input_content = ''if isinstance(content, list):if '\r' or '\n' in content:input_content = ''.join(content)else:input_content = '\n'.join(content)elif isinstance(content, str):input_content = contentself.__editor.setText(input_content)# 得到当前文本def getText(self):content = self.__editor.text()content = content.replace('\r', '')return content# 得到编辑器当前状态def getStatus(self):# boolstatus = self.__editor.isModified()return status# 修改当前编辑器状态def changeStatus(self, flag):self.__editor.setModified(flag)# 得到搜索结果....def search_interface(self, keyword, *state):"""obj = QsciScintilla()flag = obj.findFirst(self,expr,re,cs,wo,wrap,forward,line,index,show,posix,cxx11)->bool:param keyword: 你的关键词:param state: 元组(***)tips -> [虽然是 Any 但默认写 bool]expr: Any, --> 匹配词 keywordre: Any, --> 是否使用正则表达式匹配 -> 默认向后搜索 regexpcs: Any, --> 是否区分大小写匹配wo: Any, --> 是否匹配整个关键词 --> 不需要完整匹配 --> Falsewrap: Any, --> 是否在匹配结束之后回到搜索起点 --> 默认是 Trueforward: bool, --> 向前搜索: False, 向后搜索: True; 一般是True即向后搜索... 这里注意不要搞反line: -1, --> 搜索的起始行号 表示从当前行开始... 0~Nindex: -1, --> 搜索的起始索引 表示从当前行的当前光标开始 0~Nshow: True, --> 是否显示搜索结果 默认高亮...显示posix: False, --> 是否使用POSIX正则表达式匹配 默认Falseusername: False, --> 是否用用户名模式匹配 我的用户名: cxx11:return: bool --> 返回一个布尔值 表明是否找到..."""return self.__editor.findFirst(keyword, *state) # booldef search_interface_(self):# 直接找下一个....return self.__editor.findNext()def send_signal(self, parameter1, parameter2=None):v1 = getattr(self.__editor, parameter1)if parameter2 is None:return self.__editor.SendScintilla(v1)else:return self.__editor.SendScintilla(v1, parameter2)def send_signal_(self, item1, item2):item3 = self.__editor.SendScintilla(item2)return self.__editor.SendScintilla(item1, item3)# 必须搭配findFirst()/findNext()食用 在目标被选中的前提下替换def replace_interface(self, keywords):self.__editor.replace(keywords)def moveCursor(self, line, index):self.__editor.setCursorPosition(line, index)def highlight_text(self, positions):start_line, start_index, end_line, end_index = positionsself.__editor.setSelectionBackgroundColor(QColor('#4169E1')) # 蓝self.__editor.setSelectionForegroundColor(QColor('#FF8C00')) # 橘self.__editor.setSelection(start_line, start_index, end_line, end_index)def multi_highlight_text(self, positions):indicator_number = 1 # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)self.__editor.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, indicator_number)self.__editor.clearIndicatorRange(0, 0, lines, indexs, indicator_number)for start_line, start_index, end_line, end_index in positions:self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETSTYLE, indicator_number,QsciScintilla.INDIC_CONTAINER)self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETFORE, indicator_number,QColor('#4169E1'))self.__editor.fillIndicatorRange(start_line, start_index, end_line, end_index, indicator_number)def clear_all_indicator_sign(self):indicator_number = 1 # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)self.__editor.clearIndicatorRange(0, 0, lines, indexs, indicator_number)def getSelectionState(self):return self.__editor.getSelection()def getCursorLocation(self):return self.__editor.getCursorPosition()
- 在
QtabWidget
里使用TextEditorWidget
类
def openfile(self):test_path = self.config_ini["main_project"]["project_name"] + self.config_ini["test"]["folder_path"]fileName, isOk = QFileDialog.getOpenFileName(self, "选取文件", test_path, "C/C++源文件 (*.c *.cpp)")path = ''name = ''if fileName:flag = self.main_detector(fileName)else:message_ = CustomMessageBox(icon=QIcon(self.ui_icon),title='提示',text='您没有选择文件!')message_.exec_()returnif flag:if isOk:path, name = split(fileName)if path:text_editor_obj = TextEditorWidget(filename=name, filepath=path)text_editor_obj.addText(content=content)self.ui.text_editor.addTab(text_editor_obj, text_editor_obj.filename)self.ui.text_editor.setCurrentWidget(text_editor_obj)
查找替换
因为那个重写的QsciScintilla
类里有自带的查找findFirst
、替换函数replace
,但是它并没有说明书,所以又遇到对手了。接下来就需要我们学会自己克服困难,比如说把参数爬下来,丢给大爹让它分析,然后我再自己写一些特殊逻辑。
提前说明:
findFirst
这个函数有多个参数,传入的方式除了关键词之外,都是bool
值,我分析得到的结果如下:
def search_interface(self, keyword, *state):"""obj = QsciScintilla()flag = obj.findFirst(self,expr,re,cs,wo,wrap,forward,line,index,show,posix,cxx11)->bool:param keyword: 你的关键词:param state: 元组(***)tips -> [虽然是 Any 但默认写 bool]expr: Any, --> 匹配词 keywordre: Any, --> 是否使用正则表达式匹配 -> 默认向后搜索 regexpcs: Any, --> 是否区分大小写匹配wo: Any, --> 是否匹配整个关键词 --> 不需要完整匹配 --> Falsewrap: Any, --> 是否在匹配结束之后回到搜索起点 --> 默认是 Trueforward: bool, --> 向前搜索: False, 向后搜索: True; 一般是True即向后搜索... 这里注意不要搞反line: -1, --> 搜索的起始行号 表示从当前行开始... 0~Nindex: -1, --> 搜索的起始索引 表示从当前行的当前光标开始 0~Nshow: True, --> 是否显示搜索结果 默认高亮...显示posix: False, --> 是否使用POSIX正则表达式匹配 默认Falseusername: False, --> 是否用用户名模式匹配 我的用户名: cxx11:return: bool --> 返回一个布尔值 表明是否找到..."""return self.__editor.findFirst(keyword, *state) # bool
replace
这个是必须在选中的情况下使用,首先用findFirst
查找选中关键词,让这些关键词处于选中状态,然后直接用self.__editor.replace(replace_word)
就自动替换完成,注意是选中状态有几个替换几个。
参数说明
区分大小写:就是根据大小写来匹配,如果输入一个全部大写的是不会匹配到小写内容的。
全部匹配:就是必须严格是那个关键词,res
只能匹配res
不能匹配res1
正则表达式匹配: 根据你输入的关键词得到那个关键词的正则表达式,根据它再查找匹配其他字符。
是否回到搜索起点:默认搜索起点是光标停留处,若不回到就不会循环查找/替换光标范围之外的。
向前/先后搜索:相对于光标停留位置向前或者向后,True
是向后
搜索行号:默认-1 默认从第一行,可以自定义,0~N-1
搜索下标:默认-1 默认第一行第一个开始,可以自定义,0~N-1
默认返回值是bool
,代表在特定位置上是否找到
范围书写
这里由于替换很简单,只写搜索
替换就是在搜索基础上替换
全部搜索:
def search_all_string(self):self.select_keywords_pos.clear()self.keywords_pos.clear()# 获取输入input_string = self.ui.input_s.currentText()# 判断重复和大小写current_tab = self.father.currentWidget()if input_string and current_tab:# 太棒了! 我逐渐理解一切。# 清空矛盾self.select_keywords_pos.clear()self.keywords_pos.clear()# 关键词positions = set() # 存储匹配的位置line = 0 # 设置起始行号为0index = 0 # 设置起始索引为0count = 0 # 匹配次数计数器forward = self.isfoward()while True:state = (self.ui.re_s.isChecked(), # regexpself.ui.cs_s.isChecked(), # csself.ui.wo_s.isChecked(), # woFalse, # 回到开始?forward, # 向前向后?line, # 行index, # 下标True, False, False)flag = current_tab.search_interface(input_string, *state)if not flag:breakfound_pos = current_tab.send_signal(parameter1='SCI_GETCURRENTPOS', parameter2=None)found_line = current_tab.send_signal(parameter1='SCI_LINEFROMPOSITION', parameter2=found_pos)found_index = found_pos - current_tab.send_signal(parameter1='SCI_POSITIONFROMLINE',parameter2=found_line) - 1if len(input_string) > 1:positions.add((found_line, found_index - len(input_string) + 1, found_line,found_index + 1)) # 记录匹配的位置(行号和索引)else:positions.add((found_line, found_index, found_line, found_index + len(input_string))) # 记录匹配的位置(行号和索引)count += 1line = found_lineindex = found_index + len(input_string)self.keywords_pos = list(positions)current_tab.multi_highlight_text(self.keywords_pos)# self.ui.msg1 && self.ui.msg2self.ui.msg1.setText(f"共搜索到关键词: '{input_string}' {count}次!")
选中搜索
def search_select_string(self):# 点击之前先清空一切阻碍self.select_keywords_pos.clear()self.keywords_pos.clear()# 获取输入input_string = self.ui.input_s.currentText()current_tab = self.father.currentWidget()if current_tab.getSelectionState() == (-1, -1, -1, -1):message_box = CustomMessageBox(icon=QIcon(self.ui_icon), title='提示', text='请先选中一个区域!')message_box.exec_()elif input_string and current_tab.getSelectionState() != (-1, -1, -1, -1):start_line = current_tab.send_signal_(Qsci.QsciScintilla.SCI_LINEFROMPOSITION,Qsci.QsciScintilla.SCI_GETSELECTIONSTART)start_index = current_tab.send_signal_(Qsci.QsciScintilla.SCI_GETCOLUMN,Qsci.QsciScintilla.SCI_GETSELECTIONSTART)end_line = current_tab.send_signal_(Qsci.QsciScintilla.SCI_LINEFROMPOSITION,Qsci.QsciScintilla.SCI_GETSELECTIONEND)end_index = current_tab.send_signal_(Qsci.QsciScintilla.SCI_GETCOLUMN,Qsci.QsciScintilla.SCI_GETSELECTIONEND)# 存储匹配的位置positions = set()count = 0current_line = start_linecurrent_index = start_indexwhile True:if current_line > end_line:breakstate = (self.ui.re_s.isChecked(), # regexpself.ui.cs_s.isChecked(), # csself.ui.wo_s.isChecked(), # woFalse, # 回到开始?self.isfoward(), # 向前向后?current_line, # 行current_index, # 下标True, False, False)if (current_index >= end_index and current_line == end_line) or (current_line > end_line):breakflag = current_tab.search_interface(input_string, *state)if flag:found_pos = current_tab.send_signal(parameter1='SCI_GETCURRENTPOS', parameter2=None)found_line = current_tab.send_signal(parameter1='SCI_LINEFROMPOSITION', parameter2=found_pos)found_index = found_pos - current_tab.send_signal(parameter1='SCI_POSITIONFROMLINE',parameter2=found_line) - 1current_line = found_linecurrent_index = found_index + len(input_string)# 再判断 因为这个先加if current_line > end_line:breakif len(input_string) > 1:positions.add((found_line, found_index - len(input_string) + 1, found_line,found_index + 1)) # 记录匹配的位置(行号和索引)else:positions.add((found_line, found_index, found_line, found_index + len(input_string))) # 记录匹配的位置(行号和索引)count += 1else:# 搜不到就需要换行....if current_index <= end_index and current_line <= end_line:current_index += len(input_string)elif current_line <= end_line and current_index > end_index:current_index = 0current_line += 1self.select_keywords_pos = list(positions)current_tab.multi_highlight_text(self.select_keywords_pos)self.ui.msg1.setText(f"共搜索到关键词: '{input_string}' {count}次!")
干货干得要缺水了!
语法树到时候更是重量级…
任重而道远…
放在另一篇里面吧…
这里是链接
不知不觉竟然写了这么多代码(嗐)
如果付出和收获对等,我也能成为最强吗?
[手搓人]大战[高亮编辑器/查找替换/函数跳跳蛙]--巅峰对决(1)相关推荐
- [手搓人]大战[高亮编辑器/查找替换/函数跳跳蛙]--巅峰对决(2)
前置知识 抽象语法树 基本介绍 AST(Abstract Syntax Tree)抽象语法树,当你有一段源代码的时候,是用于表示该源代码的抽象语法结构的树状图.对于不同的语言,有不同的抽象语法树结构, ...
- ubuntu中查找文件后高亮_vim查找替换及取消高亮
查找替换的格式如下: :[range]s[ubstitute]/{pattern}/{string}/[flags] [count] range可以是 . 点号表示在当前行查找(这是默认的range ...
- PostgreSQL 查找替换函数
介绍 PostgreSQL 替换函数,这些函数在字符串中搜索子字符串并将其替换为新的子字符串. PostgreSQL REPLACE 函数 有时,您想搜索列中的字符串并将其替换为新字符串,例如替换过时 ...
- Excel字符函数(5):REPLACE、SUBSTITUTE查找替换函数之区别
文本字符串中用 new_text 替换 old_text. 如果需要在某一文本字符串中替换指定的文本,使用函数 SUBSTITUTE: 如果需要在某一文本字符串中替换特定位置处的任意文本,使用函数 R ...
- html编辑器查找与替换,织梦kindeditor文本编辑器增加“查找替换”功能
织梦kindeditor文本编辑器增加"查找替换"功能效果演示 1.items 里面增加 search 按钮 ['source','|','undo','redo','|','pr ...
- 找不到 查找_当心Excel查找替换错误,别犯“台风致山东全省人死亡”的错误
哈喽,大家好!我是爱踢汪.最近让大家最关注的一定是台风利奇马吧,全国人民的心都为此揪在了一起,各大平台也都纷纷关注.近日,腾讯视频可以说闹了个笑话,在对台风的报道中,竟然说台风利奇马已致全省人死亡,这 ...
- Vim查找替换操作 --- 查找和替换
查找替换 查找和替换是编辑器中最常用的功能之一,在普通编辑器当中查找替换时,你可能需要先移动鼠标在菜单中点击查找的功能,输入查找内容,再点击确认查找.而在vim中,所有的操作只需要敲击几下键盘就行了, ...
- 狂肝10个月手搓GPU,他们在《我的世界》里面玩《我的世界》
梦晨 衡宇 萧箫 发自 凹非寺 量子位 | 公众号 QbitAI 自从有人在<我的世界>里用红石电路造出CPU,就流传着一个梗: 总有一天,这帮红石佬能在我的世界里玩上我的世界. 这一天, ...
- 手柄映射键盘_“吃鸡”直接匹配“手搓”玩家?北通G2是一款非常好用的手柄...
大家好,欢迎来到<刺激实战教室>,我是你们的老朋友刺激哥. 作为一名吃鸡手游的爱好者,刺激哥的水平虽然并不见得有多好,但入手的游戏手柄可是真的一点都不少. 前前后后,接连入手了数款手机手柄 ...
最新文章
- Ajax实现在textbox中输入内容,动态从数据库中模糊查询显示到下拉框中
- Python str类型方法实例概述及常用方法——04
- python父类和子类_python子类父类
- Siamese-RPN目标跟踪算法
- Java中Volatile关键字详解
- 在Linux下安装配置phpMyAdmin步骤
- JavaScript发布订阅者模式
- SpringBoot整合Mybatis-Plus分页失效,Mybatis-Plus 3.4.1分页插件失效踩坑
- Open Source Blog 开源ASP.NET/C# 博客平台 v2.5 发布(提供源码下载)
- python矩阵中插入矩阵_Python | 矩阵的痕迹
- 墨天轮社区专属福利:与作者互动问答,民工哥全新力作《Linux系统运维指南:从入门到企业实战》送上!...
- c语言中浮点数如何声明,C语言中浮点数定义和文本处理的配合
- ocp认证考试指南第一章
- 学习C++项目——mysql 数据库知识学习(关于 mysql 8.0 版以后基础部分学习)
- Sql Sever 注册服务器 [SQL Server]
- 计算机基础综合知识试题及答案,计算机基础综合知识试题及答案
- 安装SQL 2000挂起的解决办法
- 6英寸划片机 陆芯3252半自动单轴晶圆切割机
- springnbsp;contextnbsp;初始化两次导致dub…
- 工作杂谈之说说工作中的二宗罪