如何设置 QTextDocument.FindFlag 以将搜索模式设置为在 PyQt6 中跨多行搜索

huangapple go评论57阅读模式
英文:

how to setup the QTextDocument.FindFlag to set the search mode to search across multiple lines in PyQt6

问题

# Set the QTextDocument.FindFlag to search across multiple lines
search_flag = QTextDocument.FindFlag(0)
search_flag |= QTextDocument.FindFlag(1)

这段代码用于设置QTextDocument.FindFlag,以便在多行中搜索。

search_text = 'A\nB'

这是要搜索的文本。

cursor = self.textEdit.document().find(search_text, QTextCursor(), search_flag)

这行代码用于查找文本,然后将光标移到找到的文本位置。

print("Could not find the search text")

这是在找不到搜索文本时打印的消息。

请注意,尽管代码中已经设置了QTextDocument.FindFlag以支持跨多行搜索,但在您提供的示例中,由于文本编辑器中的文本与实际搜索文本不匹配,所以找不到匹配。确保在search_text中指定要搜索的确切文本以使代码正常工作。

英文:

If the search text is spread across two lines, separated by '\n' in a QTextEdit widget, how to find it using the find() function, how to setup the QTextDocument.FindFlag to set the search mode to search across multiple lines.

from PyQt6.QtWidgets import QWidget, QApplication, QMainWindow, QTextEdit, QPushButton, QVBoxLayout
from PyQt6.QtGui import QTextCursor, QTextDocument
import sys

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.textEdit = QTextEdit()
        self.textEdit.setText('A\nB')

        self.pushButton = QPushButton("Find")
        self.pushButton.clicked.connect(self.findText)

        vbox = QVBoxLayout()
        vbox.addWidget(self.textEdit)
        vbox.addWidget(self.pushButton)

        self.setLayout(vbox)


    def findText(self):
        search_text = 'A\nB'

        # Set the QTextDocument.FindFlag to search across multiple lines
        search_flag = QTextDocument.FindFlag(0)
        search_flag |= QTextDocument.FindFlag(1)

        # Find the text using the QTextCursor
        cursor = self.textEdit.document().find(search_text, QTextCursor(), search_flag)

        if not cursor.isNull():
            self.textEdit.setTextCursor(cursor)
            self.textEdit.ensureCursorVisible()
        else:
            print("Could not find the search text")


def except_hook(cls, exception, traceback):
    sys.__excepthook__(cls, exception, traceback)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.excepthook = except_hook
    sys.exit(app.exec())

but the code finds nothing, please verify

答案1

得分: 1

不起作用的原因是您尝试搜索“新行”字符,但在QTextDocument中不存在该字符:在使用setText()时,给定的文本被解释为纯文本或HTML,并在QTextDocument结构中转换

实际上,新行字符实际上创建了一个新文本块(段落),类似于HTML中使用的<p></p>标签。实际上,如果尝试打印文本编辑器的toHtml(),您将看到以下内容:

<p style="...">A</p>
<p style="...">B</p>

当调用find()时,它仅在每个QTextBlock的文本边界内搜索(包括搜索一个单独段落的重载函数)。

要实现您想要的操作的唯一方法是查找一个包括段落末尾的字母的模式,这只能通过使用正则表达式来完成。一旦找到匹配,然后需要转到下一个文本块,并确保第一个字母与搜索模式的其余部分匹配。

请注意,当使用换行符<br>)时,情况不同。

那种情况下,QTextDocument使用特殊字符\u2028,它只会在同一文本块内创建换行符。在这种情况下,您可以使用简单的字符串搜索,考虑上述字符。

总结所有这些:

    def findText(self):
        doc = self.textEdit.document()
        cursor = doc.find('A\u2028B') # 用于<br>
        if cursor.isNull():
            while True:
                cursor = doc.find(QRegExp('A$'), cursor)
                if cursor.isNull() or cursor.atEnd():
                    return
                postCursor = QTextCursor(cursor)
                postCursor.movePosition(postCursor.MoveOperation.NextBlock)
                postCursor.select(postCursor.SelectionType.LineUnderCursor)
                if postCursor.selectedText().startswith('B'):
                    break
            cursor.setPosition(
                postCursor.selectionEnd(), cursor.MoveMode.KeepAnchor)

        if not cursor.isNull():
            self.textEdit.setTextCursor(cursor)
英文:

It does not work because you are trying to search for a "new line" character, but that does not exist in the QTextDocument: when using setText(), the given text is interpreted as either plain text or HTML and converted in a QTextDocument structure.

The new line character actually creates a new text block (a paragraph), similarly to the <p></p> tags used in HTML. In fact, if you try to print toHtml() of the text edit, you will see the following:

<p style="...">A</p>
<p style="...">B</p>

When find() is called, it only searches within the text boundaries of each QTextBlock (including the overloaded functions that search within a single paragraph).

The only way to do what you want to achieve is to find a pattern that includes the letter at the end of a paragraph, and this can only be done by using a regular expression. Once you've found a match, you then need to go to the next block and ensure that the first letter matches the rest of the search pattern.

Note that the above is not the same when using a line break (<br>).

In that case, QTextDocument uses the special character \u2028, which only creates a line break within the same text block. In that case, you can use a simple string search considering the above character.

To sum up all this:

    def findText(self):
        doc = self.textEdit.document()
        cursor = doc.find('A\u2028B') # for <br>
        if cursor.isNull():
            while True:
                cursor = doc.find(QRegExp('A$'), cursor)
                if cursor.isNull() or cursor.atEnd():
                    return
                postCursor = QTextCursor(cursor)
                postCursor.movePosition(postCursor.MoveOperation.NextBlock)
                postCursor.select(postCursor.SelectionType.LineUnderCursor)
                if postCursor.selectedText().startswith('B'):
                    break
            cursor.setPosition(
                postCursor.selectionEnd(), cursor.MoveMode.KeepAnchor)

        if not cursor.isNull():
            self.textEdit.setTextCursor(cursor)

huangapple
  • 本文由 发表于 2023年3月9日 20:54:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684915.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定