Guido van Rossum | 9a8cb84 | 1997-04-03 00:04:51 +0000 | [diff] [blame] | 1 | """Basic regular expression demostration facility. |
| 2 | |
| 3 | This displays a window with two type-in boxes. In the top box, you enter a |
| 4 | regular expression. In the bottom box, you enter a string. The first |
| 5 | match in the string of the regular expression is highlighted with a yellow |
| 6 | background (or red if the match is empty -- then the character at the match |
| 7 | is highlighted). The highlighting is continuously updated. At the bottom |
| 8 | are a number of checkboxes which control the regular expression syntax used |
| 9 | (see the regex_syntax module for descriptions). When there's no match, or |
| 10 | when the regular expression is syntactically incorrect, an error message is |
| 11 | displayed. |
| 12 | |
| 13 | """ |
| 14 | |
| 15 | from Tkinter import * |
| 16 | import regex |
| 17 | import regex_syntax |
| 18 | |
| 19 | class RegexDemo: |
| 20 | |
| 21 | def __init__(self, master): |
| 22 | self.master = master |
| 23 | self.topframe = Frame(self.master) |
| 24 | self.topframe.pack(fill=X) |
| 25 | self.promptdisplay = Label(self.topframe, text="Enter a string:") |
| 26 | self.promptdisplay.pack(side=LEFT) |
| 27 | self.statusdisplay = Label(self.topframe, text="", anchor=W) |
| 28 | self.statusdisplay.pack(side=LEFT, fill=X) |
| 29 | self.regexdisplay = Entry(self.master) |
| 30 | self.regexdisplay.pack(fill=X) |
| 31 | self.regexdisplay.focus_set() |
| 32 | self.labeldisplay = Label(self.master, anchor=W, |
| 33 | text="Enter a string:") |
| 34 | self.labeldisplay.pack(fill=X) |
| 35 | self.labeldisplay.pack(fill=X) |
| 36 | self.stringdisplay = Text(self.master, width=60, height=4) |
| 37 | self.stringdisplay.pack(fill=BOTH, expand=1) |
| 38 | self.stringdisplay.tag_configure("hit", background="yellow") |
| 39 | self.addoptions() |
| 40 | self.regexdisplay.bind('<Key>', self.recompile) |
| 41 | self.stringdisplay.bind('<Key>', self.reevaluate) |
| 42 | self.compiled = None |
| 43 | self.recompile() |
| 44 | btags = self.regexdisplay.bindtags() |
| 45 | self.regexdisplay.bindtags(btags[1:] + btags[:1]) |
| 46 | btags = self.stringdisplay.bindtags() |
| 47 | self.stringdisplay.bindtags(btags[1:] + btags[:1]) |
| 48 | |
| 49 | def addoptions(self): |
| 50 | self.frames = [] |
| 51 | self.boxes = [] |
| 52 | self.vars = [] |
| 53 | for name in ( 'RE_NO_BK_PARENS', |
| 54 | 'RE_NO_BK_VBAR', |
| 55 | 'RE_BK_PLUS_QM', |
| 56 | 'RE_TIGHT_VBAR', |
| 57 | 'RE_NEWLINE_OR', |
| 58 | 'RE_CONTEXT_INDEP_OPS'): |
| 59 | if len(self.boxes) % 3 == 0: |
| 60 | frame = Frame(self.master) |
| 61 | frame.pack(fill=X) |
| 62 | self.frames.append(frame) |
| 63 | val = getattr(regex_syntax, name) |
| 64 | var = IntVar() |
| 65 | box = Checkbutton(frame, |
| 66 | variable=var, text=name, |
| 67 | offvalue=0, onvalue=val, |
| 68 | command=self.newsyntax) |
| 69 | box.pack(side=LEFT) |
| 70 | self.boxes.append(box) |
| 71 | self.vars.append(var) |
| 72 | |
| 73 | def newsyntax(self): |
| 74 | syntax = 0 |
| 75 | for var in self.vars: |
| 76 | syntax = syntax | var.get() |
| 77 | regex.set_syntax(syntax) |
| 78 | self.recompile() |
| 79 | |
| 80 | def recompile(self, event=None): |
| 81 | try: |
| 82 | self.compiled = regex.compile(self.regexdisplay.get()) |
| 83 | self.statusdisplay.config(text="") |
| 84 | except regex.error, msg: |
| 85 | self.compiled = None |
| 86 | self.statusdisplay.config(text="regex.error: %s" % str(msg)) |
| 87 | self.reevaluate() |
| 88 | |
| 89 | def reevaluate(self, event=None): |
| 90 | try: |
| 91 | self.stringdisplay.tag_remove("hit", "1.0", END) |
| 92 | except TclError: |
| 93 | pass |
| 94 | if not self.compiled: |
| 95 | return |
| 96 | text = self.stringdisplay.get("1.0", END) |
| 97 | i = self.compiled.search(text) |
| 98 | if i < 0: |
| 99 | self.statusdisplay.config(text="(no match)") |
| 100 | else: |
| 101 | self.statusdisplay.config(text="") |
| 102 | regs = self.compiled.regs |
| 103 | first, last = regs[0] |
| 104 | if last == first: |
| 105 | last = first+1 |
| 106 | self.stringdisplay.tag_configure("hit", |
| 107 | background="red") |
| 108 | else: |
| 109 | self.stringdisplay.tag_configure("hit", |
| 110 | background="yellow") |
| 111 | pfirst = "1.0 + %d chars" % first |
| 112 | plast = "1.0 + %d chars" % last |
| 113 | self.stringdisplay.tag_add("hit", pfirst, plast) |
| 114 | self.stringdisplay.yview_pickplace(pfirst) |
| 115 | |
| 116 | |
| 117 | |
| 118 | # Main function, run when invoked as a stand-alone Python program. |
| 119 | |
| 120 | def main(): |
| 121 | root = Tk() |
| 122 | demo = RegexDemo(root) |
| 123 | root.protocol('WM_DELETE_WINDOW', root.quit) |
| 124 | root.mainloop() |
| 125 | |
| 126 | if __name__ == '__main__': |
| 127 | main() |