"""Replace dialog for IDLE. Inherits SearchDialogBase for GUI.Uses idlelib.searchengine.SearchEngine for search capability.Defines various replace related functions like replace, replace all,and replace+find."""import refrom tkinter import StringVar, TclErrorfrom idlelib.searchbase import SearchDialogBasefrom idlelib import searchenginedef replace(text):"""Create or reuse a singleton ReplaceDialog instance.The singleton dialog saves user entries and preferencesacross instances.Args:text: Text widget containing the text to be searched."""root = text._root()engine = searchengine.get(root)if not hasattr(engine, "_replacedialog"):engine._replacedialog = ReplaceDialog(root, engine)dialog = engine._replacedialogdialog.open(text)class ReplaceDialog(SearchDialogBase):"Dialog for finding and replacing a pattern in text."title = "Replace Dialog"icon = "Replace"def __init__(self, root, engine):"""Create search dialog for finding and replacing text.Uses SearchDialogBase as the basis for the GUI and asearchengine instance to prepare the search.Attributes:replvar: StringVar containing 'Replace with:' value.replent: Entry widget for replvar. Created increate_entries().ok: Boolean used in searchengine.search_text to indicatewhether the search includes the selection."""super().__init__(root, engine)self.replvar = StringVar(root)def open(self, text):"""Make dialog visible on top of others and ready to use.Also, highlight the currently selected text and set thesearch to include the current selection (self.ok).Args:text: Text widget being searched."""SearchDialogBase.open(self, text)try:first = text.index("sel.first")except TclError:first = Nonetry:last = text.index("sel.last")except TclError:last = Nonefirst = first or text.index("insert")last = last or firstself.show_hit(first, last)self.ok = Truedef create_entries(self):"Create base and additional label and text entry widgets."SearchDialogBase.create_entries(self)self.replent = self.make_entry("Replace with:", self.replvar)[0]def create_command_buttons(self):"""Create base and additional command buttons.The additional buttons are for Find, Replace,Replace+Find, and Replace All."""SearchDialogBase.create_command_buttons(self)self.make_button("Find", self.find_it)self.make_button("Replace", self.replace_it)self.make_button("Replace+Find", self.default_command, isdef=True)self.make_button("Replace All", self.replace_all)def find_it(self, event=None):"Handle the Find button."self.do_find(False)def replace_it(self, event=None):"""Handle the Replace button.If the find is successful, then perform replace."""if self.do_find(self.ok):self.do_replace()def default_command(self, event=None):"""Handle the Replace+Find button as the default command.First performs a replace and then, if the replace wassuccessful, a find next."""if self.do_find(self.ok):if self.do_replace(): # Only find next match if replace succeeded.# A bad re can cause it to fail.self.do_find(False)def _replace_expand(self, m, repl):"Expand replacement text if regular expression."if self.engine.isre():try:new = m.expand(repl)except re.error:self.engine.report_error(repl, 'Invalid Replace Expression')new = Noneelse:new = replreturn newdef replace_all(self, event=None):"""Handle the Replace All button.Search text for occurrences of the Find value and replaceeach of them. The 'wrap around' value controls the startpoint for searching. If wrap isn't set, then the searchingstarts at the first occurrence after the current selection;if wrap is set, the replacement starts at the first line.The replacement is always done top-to-bottom in the text."""prog = self.engine.getprog()if not prog:returnrepl = self.replvar.get()text = self.textres = self.engine.search_text(text, prog)if not res:self.bell()returntext.tag_remove("sel", "1.0", "end")text.tag_remove("hit", "1.0", "end")line = res[0]col = res[1].start()if self.engine.iswrap():line = 1col = 0ok = Truefirst = last = None# XXX ought to replace circular instead of top-to-bottom when wrappingtext.undo_block_start()while True:res = self.engine.search_forward(text, prog, line, col,wrap=False, ok=ok)if not res:breakline, m = reschars = text.get("%d.0" % line, "%d.0" % (line+1))orig = m.group()new = self._replace_expand(m, repl)if new is None:breaki, j = m.span()first = "%d.%d" % (line, i)last = "%d.%d" % (line, j)if new == orig:text.mark_set("insert", last)else:text.mark_set("insert", first)if first != last:text.delete(first, last)if new:text.insert(first, new)col = i + len(new)ok = Falsetext.undo_block_stop()if first and last:self.show_hit(first, last)self.close()def do_find(self, ok=False):"""Search for and highlight next occurrence of pattern in text.No text replacement is done with this option."""if not self.engine.getprog():return Falsetext = self.textres = self.engine.search_text(text, None, ok)if not res:self.bell()return Falseline, m = resi, j = m.span()first = "%d.%d" % (line, i)last = "%d.%d" % (line, j)self.show_hit(first, last)self.ok = Truereturn Truedef do_replace(self):"Replace search pattern in text with replacement value."prog = self.engine.getprog()if not prog:return Falsetext = self.texttry:first = pos = text.index("sel.first")last = text.index("sel.last")except TclError:pos = Noneif not pos:first = last = pos = text.index("insert")line, col = searchengine.get_line_col(pos)chars = text.get("%d.0" % line, "%d.0" % (line+1))m = prog.match(chars, col)if not prog:return Falsenew = self._replace_expand(m, self.replvar.get())if new is None:return Falsetext.mark_set("insert", first)text.undo_block_start()if m.group():text.delete(first, last)if new:text.insert(first, new)text.undo_block_stop()self.show_hit(first, text.index("insert"))self.ok = Falsereturn Truedef show_hit(self, first, last):"""Highlight text between first and last indices.Text is highlighted via the 'hit' tag and the markedsection is brought into view.The colors from the 'hit' tag aren't currently shownwhen the text is displayed. This is due to the 'sel'tag being added first, so the colors in the 'sel'config are seen instead of the colors for 'hit'."""text = self.texttext.mark_set("insert", first)text.tag_remove("sel", "1.0", "end")text.tag_add("sel", first, last)text.tag_remove("hit", "1.0", "end")if first == last:text.tag_add("hit", first)else:text.tag_add("hit", first, last)text.see("insert")text.update_idletasks()def close(self, event=None):"Close the dialog and remove hit tags."SearchDialogBase.close(self, event)self.text.tag_remove("hit", "1.0", "end")def _replace_dialog(parent): # htest #from tkinter import Toplevel, Text, END, SELfrom tkinter.ttk import Frame, Buttontop = Toplevel(parent)top.title("Test ReplaceDialog")x, y = map(int, parent.geometry().split('+')[1:])top.geometry("+%d+%d" % (x, y + 175))# mock undo delegator methodsdef undo_block_start():passdef undo_block_stop():passframe = Frame(top)frame.pack()text = Text(frame, inactiveselectbackground='gray')text.undo_block_start = undo_block_starttext.undo_block_stop = undo_block_stoptext.pack()text.insert("insert","This is a sample sTring\nPlus MORE.")text.focus_set()def show_replace():text.tag_add(SEL, "1.0", END)replace(text)text.tag_remove(SEL, "1.0", END)button = Button(frame, text="Replace", command=show_replace)button.pack()if __name__ == '__main__':from unittest import mainmain('idlelib.idle_test.test_replace', verbosity=2, exit=False)from idlelib.idle_test.htest import runrun(_replace_dialog)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。