使用 QsciScintilla.findNext 的反向搜索未按预期工作
Backward search using QsciScintilla.findNext not working as expected
如果我向前搜索字母 x
(按钮 Next
),一切正常,但一旦我改变方向(按钮 Previous
),就会发生这种情况:
QsciScintilla.findFirst()
不移动选择。即,第一次按下按钮 Previous
不会执行任何操作;
QsciScintilla.findNext()
以 2 为步长移动,因此跳过一个字符。
ATM 我正在考虑将查找操作的逻辑从 C++ 转换为 Python,从而有可能解决这个问题,但很高兴知道我犯了一些新手错误,从而避免了所有额外的工作...
代码如下:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.Qsci import *
import sys
class FindAndReplace(QWidget):
def __init__(self, *arg, **kwarg):
super(self.__class__, self).__init__(*arg, **kwarg)
rows = QVBoxLayout()
self.editor = QsciScintilla()
self.editor.setText(f'{"x"*40}\n{"y"*40}\n{"z"*40}\n')
rows.addWidget(self.editor)
self.text_to_find = ''
self.state_ = tuple()
self.find = QLineEdit()
self.find_previous = QPushButton('&Previous')
self.find_next = QPushButton('&Next')
self.find_lbl = QLabel('&Find')
self.find_lbl.setBuddy(self.find)
row = QHBoxLayout()
for w in (self.find_lbl, self.find, self.find_previous, self.find_next):
row.addWidget(w)
rows.addLayout(row)
self.re = QCheckBox('&Regular expressions')
self.cs = QCheckBox('&Case sensitive')
self.wo = QCheckBox('Whole &words')
self.wrap = QCheckBox('Wrap aroun&d')
self.show_ = QCheckBox('&Unfold folded text')
self.posix = QCheckBox('POSI&X-compatible RE')
row = QHBoxLayout()
for w in (self.re, self.cs, self.wo, self.wrap, self.show_, self.posix):
row.addWidget(w)
rows.addLayout(row)
self.setLayout(rows)
self.find_previous.clicked.connect(lambda: self.findText(forward = False))
self.find_next.clicked.connect(lambda: self.findText(forward = True))
def findText(self, forward):
text_to_find = self.find.text()
state_ = ( \
self.re.isChecked(), self.cs.isChecked(),
self.wo.isChecked(), self.wrap.isChecked(),
forward, -1, -1,
self.show_.isChecked(), self.posix.isChecked(),
)
if text_to_find != self.text_to_find or state_ != self.state_:
self.text_to_find = text_to_find
self.state_ = state_
# search with new conditions.
self.editor.findFirst(text_to_find, *state_)
else:
# search with previously set conditions.
self.editor.findNext()
if __name__ == '__main__':
app = QApplication(sys.argv)
FindAndReplace().show()
sys.exit(app.exec_())
findNext
函数在我看来有问题。如果我使用 getSelection
在 findFirst
中明确输入 line
和 index
,并且完全避免使用 findNext
,一切都会按预期工作:
def findText(self, forward):
text_to_find = self.find.text()
if forward:
line, index = self.editor.getSelection()[2:]
else:
line, index = self.editor.getSelection()[:2]
state_ = (
self.re.isChecked(), self.cs.isChecked(),
self.wo.isChecked(), self.wrap.isChecked(),
forward, line, index,
self.show_.isChecked(), self.posix.isChecked(),
)
self.text_to_find = text_to_find
self.state_ = state_
self.editor.findFirst(text_to_find, *state_)
查看最新的源代码(qsciscintilla.cpp,第 1853 行)我看到了这个:
// Finally adjust the start position so that we don't find the same one again.
if (findState.forward)
findState.startpos = targend;
else if ((findState.startpos = targstart - 1) < 0)
findState.startpos = 0;
我可能误解了代码的意图,但为什么这里减一? AFAICS,这将在向后搜索时产生一个差一错误。
如果我向前搜索字母 x
(按钮 Next
),一切正常,但一旦我改变方向(按钮 Previous
),就会发生这种情况:
QsciScintilla.findFirst()
不移动选择。即,第一次按下按钮Previous
不会执行任何操作;QsciScintilla.findNext()
以 2 为步长移动,因此跳过一个字符。
ATM 我正在考虑将查找操作的逻辑从 C++ 转换为 Python,从而有可能解决这个问题,但很高兴知道我犯了一些新手错误,从而避免了所有额外的工作...
代码如下:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.Qsci import *
import sys
class FindAndReplace(QWidget):
def __init__(self, *arg, **kwarg):
super(self.__class__, self).__init__(*arg, **kwarg)
rows = QVBoxLayout()
self.editor = QsciScintilla()
self.editor.setText(f'{"x"*40}\n{"y"*40}\n{"z"*40}\n')
rows.addWidget(self.editor)
self.text_to_find = ''
self.state_ = tuple()
self.find = QLineEdit()
self.find_previous = QPushButton('&Previous')
self.find_next = QPushButton('&Next')
self.find_lbl = QLabel('&Find')
self.find_lbl.setBuddy(self.find)
row = QHBoxLayout()
for w in (self.find_lbl, self.find, self.find_previous, self.find_next):
row.addWidget(w)
rows.addLayout(row)
self.re = QCheckBox('&Regular expressions')
self.cs = QCheckBox('&Case sensitive')
self.wo = QCheckBox('Whole &words')
self.wrap = QCheckBox('Wrap aroun&d')
self.show_ = QCheckBox('&Unfold folded text')
self.posix = QCheckBox('POSI&X-compatible RE')
row = QHBoxLayout()
for w in (self.re, self.cs, self.wo, self.wrap, self.show_, self.posix):
row.addWidget(w)
rows.addLayout(row)
self.setLayout(rows)
self.find_previous.clicked.connect(lambda: self.findText(forward = False))
self.find_next.clicked.connect(lambda: self.findText(forward = True))
def findText(self, forward):
text_to_find = self.find.text()
state_ = ( \
self.re.isChecked(), self.cs.isChecked(),
self.wo.isChecked(), self.wrap.isChecked(),
forward, -1, -1,
self.show_.isChecked(), self.posix.isChecked(),
)
if text_to_find != self.text_to_find or state_ != self.state_:
self.text_to_find = text_to_find
self.state_ = state_
# search with new conditions.
self.editor.findFirst(text_to_find, *state_)
else:
# search with previously set conditions.
self.editor.findNext()
if __name__ == '__main__':
app = QApplication(sys.argv)
FindAndReplace().show()
sys.exit(app.exec_())
findNext
函数在我看来有问题。如果我使用 getSelection
在 findFirst
中明确输入 line
和 index
,并且完全避免使用 findNext
,一切都会按预期工作:
def findText(self, forward):
text_to_find = self.find.text()
if forward:
line, index = self.editor.getSelection()[2:]
else:
line, index = self.editor.getSelection()[:2]
state_ = (
self.re.isChecked(), self.cs.isChecked(),
self.wo.isChecked(), self.wrap.isChecked(),
forward, line, index,
self.show_.isChecked(), self.posix.isChecked(),
)
self.text_to_find = text_to_find
self.state_ = state_
self.editor.findFirst(text_to_find, *state_)
查看最新的源代码(qsciscintilla.cpp,第 1853 行)我看到了这个:
// Finally adjust the start position so that we don't find the same one again.
if (findState.forward)
findState.startpos = targend;
else if ((findState.startpos = targstart - 1) < 0)
findState.startpos = 0;
我可能误解了代码的意图,但为什么这里减一? AFAICS,这将在向后搜索时产生一个差一错误。