blob: 1502b9df5c73d3673fe329e46f142fdcf7c56a82 [file] [log] [blame]
Guido van Rossum0da45c41998-05-29 19:57:47 +00001"""Basic regular expression demostration facility (Perl style syntax).
2
3This displays a window with two type-in boxes. In the top box, you
4enter a Perl style regular expression. In the bottom box, you enter a
5string. The first match in the string of the regular expression is
6highlighted with a yellow background (or red if the match is empty --
7then the character at the match is highlighted). The highlighting is
8continuously updated. At the bottom are a number of checkboxes which
9control the regular expression options used (see the re module for
10descriptions). When there's no match, or when the regular expression
11is syntactically incorrect, an error message is displayed.
12
13"""
14
15from Tkinter import *
16import re
17
18class ReDemo:
19
20 def __init__(self, master):
21 self.master = master
22
23 self.promptdisplay = Label(self.master, anchor=W,
24 text="Enter a Perl-style regular expression:")
25 self.promptdisplay.pack(side=TOP, fill=X)
26
27 self.regexdisplay = Entry(self.master)
28 self.regexdisplay.pack(fill=X)
29 self.regexdisplay.focus_set()
30
31 self.addoptions()
32
33 self.statusdisplay = Label(self.master, text="", anchor=W)
34 self.statusdisplay.pack(side=TOP, fill=X)
35
36 self.labeldisplay = Label(self.master, anchor=W,
37 text="Enter a string to search:")
38 self.labeldisplay.pack(fill=X)
39 self.labeldisplay.pack(fill=X)
40
41 self.showframe = Frame(master)
42 self.showframe.pack(fill=X, anchor=W)
43
44 self.showvar = StringVar(master)
45 self.showvar.set("first")
46
47 self.showfirstradio = Radiobutton(self.showframe,
48 text="Highlight first match",
49 variable=self.showvar,
50 value="first",
51 command=self.recompile)
52 self.showfirstradio.pack(side=LEFT)
53
54 self.showallradio = Radiobutton(self.showframe,
55 text="Highlight all matches",
56 variable=self.showvar,
57 value="all",
58 command=self.recompile)
59 self.showallradio.pack(side=LEFT)
60
61 self.stringdisplay = Text(self.master, width=60, height=4)
62 self.stringdisplay.pack(fill=BOTH, expand=1)
63 self.stringdisplay.tag_configure("hit", background="yellow")
64
65 self.grouplabel = Label(self.master, text="Groups:", anchor=W)
66 self.grouplabel.pack(fill=X)
67
68 self.grouplist = Listbox(self.master)
69 self.grouplist.pack(expand=1, fill=BOTH)
70
71 self.regexdisplay.bind('<Key>', self.recompile)
72 self.stringdisplay.bind('<Key>', self.reevaluate)
73
74 self.compiled = None
75 self.recompile()
76
77 btags = self.regexdisplay.bindtags()
78 self.regexdisplay.bindtags(btags[1:] + btags[:1])
79
80 btags = self.stringdisplay.bindtags()
81 self.stringdisplay.bindtags(btags[1:] + btags[:1])
82
83 def addoptions(self):
84 self.frames = []
85 self.boxes = []
86 self.vars = []
87 for name in ('IGNORECASE',
88 'LOCALE',
89 'MULTILINE',
90 'DOTALL',
91 'VERBOSE'):
92 if len(self.boxes) % 3 == 0:
93 frame = Frame(self.master)
94 frame.pack(fill=X)
95 self.frames.append(frame)
96 val = getattr(re, name)
97 var = IntVar()
98 box = Checkbutton(frame,
99 variable=var, text=name,
100 offvalue=0, onvalue=val,
101 command=self.recompile)
102 box.pack(side=LEFT)
103 self.boxes.append(box)
104 self.vars.append(var)
105
106 def getflags(self):
107 flags = 0
108 for var in self.vars:
109 flags = flags | var.get()
110 flags = flags
111 return flags
112
113 def recompile(self, event=None):
114 try:
115 self.compiled = re.compile(self.regexdisplay.get(),
116 self.getflags())
117 bg = self.promptdisplay['background']
118 self.statusdisplay.config(text="", background=bg)
119 except re.error, msg:
120 self.compiled = None
121 self.statusdisplay.config(
122 text="re.error: %s" % str(msg),
123 background="red")
124 self.reevaluate()
125
126 def reevaluate(self, event=None):
127 try:
128 self.stringdisplay.tag_remove("hit", "1.0", END)
129 except TclError:
130 pass
131 try:
132 self.stringdisplay.tag_remove("hit0", "1.0", END)
133 except TclError:
134 pass
135 self.grouplist.delete(0, END)
136 if not self.compiled:
137 return
138 self.stringdisplay.tag_configure("hit", background="yellow")
139 self.stringdisplay.tag_configure("hit0", background="orange")
140 text = self.stringdisplay.get("1.0", END)
141 last = 0
142 nmatches = 0
143 while last <= len(text):
144 m = self.compiled.search(text, last)
145 if m is None:
146 break
147 first, last = m.span()
148 if last == first:
149 last = first+1
150 tag = "hit0"
151 else:
152 tag = "hit"
153 pfirst = "1.0 + %d chars" % first
154 plast = "1.0 + %d chars" % last
155 self.stringdisplay.tag_add(tag, pfirst, plast)
156 if nmatches == 0:
157 self.stringdisplay.yview_pickplace(pfirst)
158 groups = list(m.groups())
159 groups.insert(0, m.group())
160 for i in range(len(groups)):
161 g = "%2d: %s" % (i, `groups[i]`)
162 self.grouplist.insert(END, g)
163 nmatches = nmatches + 1
164 if self.showvar.get() == "first":
165 break
166
167 if nmatches == 0:
168 self.statusdisplay.config(text="(no match)",
169 background="yellow")
170 else:
171 self.statusdisplay.config(text="")
172
173
174# Main function, run when invoked as a stand-alone Python program.
175
176def main():
177 root = Tk()
178 demo = ReDemo(root)
179 root.protocol('WM_DELETE_WINDOW', root.quit)
180 root.mainloop()
181
182if __name__ == '__main__':
183 main()