📄 index.lxp@lxpwrap=x6734_252ehtm.htm
字号:
function. The same instance of the dialog can be used for different documents.</P><PRECLASS="PROGRAMLISTING"> def showFind(self, document, view): FrmFindReplace.show(self) self.bnFind.setDefault(TRUE) self.setCaption("Find in " + document.title()) self.bnReplaceNext.hide() self.bnReplaceAll.hide() self.grpReplace.hide() self.cmbFind.setFocus() self.init(document, view) def showReplace(self, document, view): FrmFindReplace.show(self) self.setCaption("Find and replace in " + document.title()) self.bnReplaceNext.show() self.bnReplaceNext.setDefault(TRUE) self.bnReplaceAll.show() self.grpReplace.show() self.cmbFind.setFocus() self.init(document, view) </PRE><P>As we discussed above, there are two show functions (<TTCLASS="FUNCTION">showFind()</TT> and <TTCLASS="FUNCTION">showReplace</TT>), each hides or shows the widgets that are relevant. The show functions also call the initialization function <TTCLASS="FUNCTION">init()</TT>.</P><PRECLASS="PROGRAMLISTING"> def init(self, document, view): self.document = document self.view = view if view.hasSelection(): self.chkSelection.setChecked(TRUE) self.setFindExtent() </PRE><P>The <TTCLASS="FUNCTION">init()</TT> function sets the document and view variables. Most of the work is done directly on the view, making use of its functionality for inserting, deleting and selecting text. This is because whenever a string is found, it will be selected. Asking the document to select a string will cause it to select the string in all views of that document, which would be quite confusing for the user.</P><P>If there is already a selection present in the view, the "find in selection" checkbox is checked. This is convenient, because when a user presses find after having selected a section of text, he most likely wants the search to be performed in that selection only.</P><P>The function <TTCLASS="FUNCTION">setFindExtent()</TT> (which we will examine in detail later in this section) determines which part of the text should be searched: from the cursor position to the end, to the beginning, or between the beginning and end of a selection. The find routine keeps track of where it is within a search extent, using the variable <TTCLASS="VARNAME">self.currentPosition</TT>, which is initially the same as the start position of the extent.</P><PRECLASS="PROGRAMLISTING"> # # Slot implementations # def slotRegExp(self): if self.radioRegexp.isChecked(): self.radioForward.setChecked(TRUE) self.grpDirection.setEnabled(FALSE) else: self.grpDirection.setEnabled(TRUE) </PRE><P>If you are using Qt 2.3, you cannot use regular expressions to search backwards. In Qt 3.0 the regular expression object <TTCLASS="CLASSNAME">QRegExp</TT> has been greatly extended, and can be used to search both forwards and backwards. When <SPANCLASS="APPLICATION">Kalam</SPAN> was written, Qt 3.0 was still in beta. Therefore, it was necessary to include code to disable the forward/backward checkboxes whenever the user selects the regular expressions search mode, and code to make forward searching the default.</P><DIVCLASS="NOTE"><BLOCKQUOTECLASS="NOTE"><P><B>On regular expressions: </B>It is quite probable that you know more about regular expressions than I do. I can't write them for toffee, and I find reading regular expressions to be even harder (despite the fact that I used to be a dab hand at Snobol). Nonetheless, regular expressions are indispensable when searching a text. Even I know how to use $ to specify the end of input or \n to specify a new line. Regular expressions are everywhere on a Unix system, and all decent editors (as well as Python, Perl and most other languages) support them. On Windows, you can enter regular expressions in the search function of Word (or so I am told).</P><P>A regular expression is nothing more than an algebraic notation for characterizing a set of strings. An expression represents a pattern that the regular expression engine can use to match text. Python comes with its own highly capable, high performance regular expression engine, compared with which the regular expression engine in Qt 2.3 is a bit puny. The regular expression engine of Qt 3.0 has been improved a lot, and is nearly as good as the Python one.</P><P>According to the Qt online documentation, the Qt 2.3 <TTCLASS="CLASSNAME">QRegExp</TT> class recognized the following primitives:</P><P></P><UL><LI><P>c - the character 'c' </P></LI><LI><P>. - any character (but only one) </P></LI><LI><P>^ - matches start of input </P></LI><LI><P>$ - matches end of input </P></LI><LI><P>[] - matches a defined set of characters. For instance, [a-z] matches all lowercase ASCII characters. Note that you can give a range with a dash (-) and negate a set with a caron (^ - [^ab] match anything that does contain neither a nor b)/ </P></LI><LI><P>c* - matches a sequence of zero or more character c's </P></LI><LI><P>c+ - matches a sequence of one or more character c's </P></LI><LI><P>c? - matches an optional character c </P></LI><LI><P>\c - escape code for special characters such as \, [, *, +, . etc. </P></LI><LI><P>\t - matches the TAB character (9) </P></LI><LI><P>\n - matches newline (10). For instance "else\n" will find all occurrence of else that are followed with a new line, and that are thus missing the obligatory closing colon (:). </P></LI><LI><P>\r - matches return (13) </P></LI><LI><P>\s - matches a white space (defined as any character for which QChar::isSpace() returns TRUE. This includes at least ASCII characters 9 (TAB), 10 (LF), 11 (VT), 12(FF), 13 (CR) and 32 (Space)). </P></LI><LI><P>\d - matches a digit (defined as any character for which QChar::isDigit() returns TRUE. This includes at least ASCII characters '0'-'9'). </P></LI><LI><P>\x1f6b - matches the character with unicode point U1f6b (hexadecimal 1f6b). \x0012 will match the ASCII/Latin1 character 0x12 (18 decimal, 12 hexadecimal). </P></LI><LI><P>\022 - matches the ASCII/Latin1 character 022 (18 decimal, 22 octal). </P></LI></UL><P>Being constitutionally unable to explain exactly <SPAN><ICLASS="EMPHASIS">how</I></SPAN> you go about creating regular expressions that work, I can only refer you to the online documentation of Python and Qt, and to the many tutorials available on the web. Qt 3.0 comes with an excellent page on regular expressions, too. Whenever I read Part I of Jurafsky and Martin's book ‘Speech and Language Processing', I have the feeling that I understand regular expressions, and I have never found that to be the case with any other text on the subject.</P><P>As a last note: both Python and Qt regular expressions work just fine with Unicode. Back to our code...</P></BLOCKQUOTE></DIV><PRECLASS="PROGRAMLISTING"> def slotCaseSensitive(self): pass def slotBeginning(self): self.setFindExtent() def slotSelection(self): self.setFindExtent() def slotForward(self): self.setFindExtent() def slotBackward(self): self.setFindExtent() </PRE><P>Whenever the user alters one of the options that influence the direction or area of search, the extent must be adapted.</P><PRECLASS="PROGRAMLISTING"> # # Extent calculations # def setSelectionExtent(self): self.startSelection = self.view.selectionStart() self.endSelection = self.view.selectionEnd() self.startPosition = self.startSelection self.endPosition = self.endSelection def setBackwardExtent(self): # Determine extent to be searched if (self.chkWholeText.isChecked()): self.endPosition = self.view.length() else: self.endPosition = self.view.getCursorPosition() self.startPosition = 0 if self.chkSelection.isChecked(): if self.view.hasSelection(): setSelectionExtent() self.currentPosition = self.endPosition def setForwardExtent(self): # Determine extent to be searched if (self.chkWholeText.isChecked()): self.startPosition = 0 else: self.startPosition = self.view.getCursorPosition() self.endPosition = self.view.length() if self.chkSelection.isChecked(): if self.view.hasSelection(): setSelectionExtent() self.currentPosition = self.startPosition def setFindExtent(self): if self.radioForward.isChecked(): self.setForwardExtent() else: self.setBackwardExtent() </PRE><P>Correctly determining which part of the text should be searched is a fairly complex task. First, there is an important difference between searching forwards and backwards, if only because of the place where searching should start. A further complication is caused by the option to search either the whole text, or from the cursor position. Note that begin and end mean the same thing with both backwards and forwards searches; it is <TTCLASS="VARNAME">currentPosition</TT>, where searching should start, that is different between forward and backward searches.</P><PRECLASS="PROGRAMLISTING"> def wrapExtentForward(self): if QMessageBox.information(self.parent(), "Kalam", "End reached. Start from beginning?", "yes", "no", None, 0, 1) == 0: self.endPosition = self.startPosition self.startPosition = 0 self.currentPosition = 0 self.slotFindNext() def wrapExtentBackward(self): if QMessageBox.information(self.parent(), "Kalam", "Begin reached. Start from end?", "yes", "no", None, 0, 1) == 0: self.startPosition = self.endPosition self.endPosition = self.view.length() self.currentPosition = self.startPosition self.previousOccurrence() self.slotFindNext() </PRE><P>Whenever the current extent has been searched, the user should be asked whether he or she wants to search the rest of the text. The functions above are different for forwards and backwards searching, too.</P><PRECLASS="PROGRAMLISTING"> # # Find functions # def nextOccurrence(self): findText = self.cmbFind.currentText() caseSensitive = self.chkCaseSensitive.isChecked() if self.radioRegexp.isChecked(): # Note differences with Qt 3.0 regExp = QRegExp(findText, caseSensitive) pos, len = regExp.match(self.view.text(), self.currentPosition, FALSE) return pos, pos+len else: pos = self.view.text().find(findText, self.currentPosition, caseSensitive) return (pos, pos + findText.length()) </PRE><P>Searching forwards can be done by plain text matching, or with regular expressions.</P><P>Regular expressions are available from both Python and PyQt. Python regular expressions (in the <TTCLASS="FILENAME">re</TT> module) work on Python strings, while PyQt regular expressions work on <TTCLASS="CLASSNAME">QString</TT>s. It is relatively inefficient to convert a <TTCLASS="CLASSNAME">QString</TT> to a Python string, so we use <TTCLASS="CLASSNAME"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -