7

I have a QTextEdit window that shows the content of a file. I would like to be able to find all matches inside the text using a regex and highlight them either by making the match background different or by changing the match text color or making it bold. How can I do this?

Eugene Sajine
  • 8,104
  • 3
  • 23
  • 28
  • `QTextEdit` accepts html tags, you can use your regex to wrap the matched text with your tags –  Dec 21 '12 at 00:19
  • 1
    @X.Jacobs, please take it easy on the suggested edits that mainly bold text. That doesn't really add anything to the question. Visit Meta for [discussion on the topic](http://meta.stackexchange.com/questions/158564/is-editing-posts-to-only-introduce-bold-emphasis-acceptable). – Michael Petrotta Dec 21 '12 at 00:25
  • something went crazy, a couple of overlapping edits on your post, sorry about that, i would suggest you though, to checkout [How to Ask](http://stackoverflow.com/questions/how-to-ask) –  Dec 21 '12 at 00:36

3 Answers3

15

I think the simplest solution to your problem is to use the cursor associated to your editor in order to do the formatting. This way you can set the foreground, the background, the font style... The following example marks the matches with a different background.

from PyQt4 import QtGui
from PyQt4 import QtCore

class MyHighlighter(QtGui.QTextEdit):
    def __init__(self, parent=None):
        super(MyHighlighter, self).__init__(parent)
        # Setup the text editor
        text = """In this text I want to highlight this word and only this word.\n""" +\
        """Any other word shouldn't be highlighted"""
        self.setText(text)
        cursor = self.textCursor()
        # Setup the desired format for matches
        format = QtGui.QTextCharFormat()
        format.setBackground(QtGui.QBrush(QtGui.QColor("red")))
        # Setup the regex engine
        pattern = "word"
        regex = QtCore.QRegExp(pattern)
        # Process the displayed document
        pos = 0
        index = regex.indexIn(self.toPlainText(), pos)
        while (index != -1):
            # Select the matched text and apply the desired format
            cursor.setPosition(index)
            cursor.movePosition(QtGui.QTextCursor.EndOfWord, 1)
            cursor.mergeCharFormat(format)
            # Move to the next match
            pos = index + regex.matchedLength()
            index = regex.indexIn(self.toPlainText(), pos)

if __name__ == "__main__":
    import sys
    a = QtGui.QApplication(sys.argv)
    t = MyHighlighter()
    t.show()
    sys.exit(a.exec_())

The code is self-explanatory but if you have any questions just ask them.

Vicent
  • 5,322
  • 2
  • 28
  • 36
6

Here is a sample of how can you highlight text in a QTextEdit:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class highlightSyntax(QSyntaxHighlighter):
    def __init__(self, listKeywords, parent=None):
        super(highlightSyntax, self).__init__(parent)
        brush   = QBrush(Qt.darkBlue, Qt.SolidPattern)
        keyword = QTextCharFormat()
        keyword.setForeground(brush)
        keyword.setFontWeight(QFont.Bold)

        self.highlightingRules = [  highlightRule(QRegExp("\\b" + key + "\\b"), keyword)
                                    for key in listKeywords
                                    ]

    def highlightBlock(self, text):
        for rule in self.highlightingRules:
            expression = QRegExp(rule.pattern)
            index      = expression.indexIn(text)

            while index >= 0:
              length = expression.matchedLength()
              self.setFormat(index, length, rule.format)
              index = text.indexOf(expression, index + length)

        self.setCurrentBlockState(0)  

class highlightRule(object):
    def __init__(self, pattern, format):
        self.pattern = pattern
        self.format  = format

class highlightTextEdit(QTextEdit):
    def __init__(self, fileInput, listKeywords, parent=None):
        super(highlightTextEdit, self).__init__(parent)
        highlightSyntax(QStringList(listKeywords), self)

        with open(fileInput, "r") as fInput:
            self.setPlainText(fInput.read())        

if __name__ == "__main__":
    import  sys

    app = QApplication(sys.argv)
    main = highlightTextEdit("/path/to/file", ["foo", "bar", "baz"])
    main.show()
    sys.exit(app.exec_())
1

QT5 has updated the RegEx, see QRegularExpression https://dangelog.wordpress.com/2012/04/07/qregularexpression/

I have updated the first example using cursors.

Note the following changes:

  1. This doesn't wrap an edit, but uses the edit box inside, it could easily be changed to allow you to pass in the edit widget.

  2. This does a proper regex find, not just a single word.

    def do_find_highlight(self, pattern):
        cursor = self.editor.textCursor()
        # Setup the desired format for matches
        format = QTextCharFormat()
        format.setBackground(QBrush(QColor("red")))
        
        # Setup the regex engine
        re = QRegularExpression(pattern)
        i = re.globalMatch(self.editor.toPlainText()) # QRegularExpressionMatchIterator

        # iterate through all the matches and highlight
        while i.hasNext():
            match = i.next() #QRegularExpressionMatch

            # Select the matched text and apply the desired format
            cursor.setPosition(match.capturedStart(), QTextCursor.MoveAnchor)
            cursor.setPosition(match.capturedEnd(), QTextCursor.KeepAnchor)
            cursor.mergeCharFormat(format)
QuentinJS
  • 162
  • 1
  • 9