You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.8 KiB
174 lines
5.8 KiB
4 years ago
|
#!/usr/bin/env python3
|
||
|
|
||
|
"""Basic regular expression demonstration facility (Perl style syntax)."""
|
||
|
|
||
|
from tkinter import *
|
||
|
import re
|
||
|
|
||
|
class ReDemo:
|
||
|
|
||
|
def __init__(self, master):
|
||
|
self.master = master
|
||
|
|
||
|
self.promptdisplay = Label(self.master, anchor=W,
|
||
|
text="Enter a Perl-style regular expression:")
|
||
|
self.promptdisplay.pack(side=TOP, fill=X)
|
||
|
|
||
|
self.regexdisplay = Entry(self.master)
|
||
|
self.regexdisplay.pack(fill=X)
|
||
|
self.regexdisplay.focus_set()
|
||
|
|
||
|
self.addoptions()
|
||
|
|
||
|
self.statusdisplay = Label(self.master, text="", anchor=W)
|
||
|
self.statusdisplay.pack(side=TOP, fill=X)
|
||
|
|
||
|
self.labeldisplay = Label(self.master, anchor=W,
|
||
|
text="Enter a string to search:")
|
||
|
self.labeldisplay.pack(fill=X)
|
||
|
self.labeldisplay.pack(fill=X)
|
||
|
|
||
|
self.showframe = Frame(master)
|
||
|
self.showframe.pack(fill=X, anchor=W)
|
||
|
|
||
|
self.showvar = StringVar(master)
|
||
|
self.showvar.set("first")
|
||
|
|
||
|
self.showfirstradio = Radiobutton(self.showframe,
|
||
|
text="Highlight first match",
|
||
|
variable=self.showvar,
|
||
|
value="first",
|
||
|
command=self.recompile)
|
||
|
self.showfirstradio.pack(side=LEFT)
|
||
|
|
||
|
self.showallradio = Radiobutton(self.showframe,
|
||
|
text="Highlight all matches",
|
||
|
variable=self.showvar,
|
||
|
value="all",
|
||
|
command=self.recompile)
|
||
|
self.showallradio.pack(side=LEFT)
|
||
|
|
||
|
self.stringdisplay = Text(self.master, width=60, height=4)
|
||
|
self.stringdisplay.pack(fill=BOTH, expand=1)
|
||
|
self.stringdisplay.tag_configure("hit", background="yellow")
|
||
|
|
||
|
self.grouplabel = Label(self.master, text="Groups:", anchor=W)
|
||
|
self.grouplabel.pack(fill=X)
|
||
|
|
||
|
self.grouplist = Listbox(self.master)
|
||
|
self.grouplist.pack(expand=1, fill=BOTH)
|
||
|
|
||
|
self.regexdisplay.bind('<Key>', self.recompile)
|
||
|
self.stringdisplay.bind('<Key>', self.reevaluate)
|
||
|
|
||
|
self.compiled = None
|
||
|
self.recompile()
|
||
|
|
||
|
btags = self.regexdisplay.bindtags()
|
||
|
self.regexdisplay.bindtags(btags[1:] + btags[:1])
|
||
|
|
||
|
btags = self.stringdisplay.bindtags()
|
||
|
self.stringdisplay.bindtags(btags[1:] + btags[:1])
|
||
|
|
||
|
def addoptions(self):
|
||
|
self.frames = []
|
||
|
self.boxes = []
|
||
|
self.vars = []
|
||
|
for name in ('IGNORECASE',
|
||
|
'LOCALE',
|
||
|
'MULTILINE',
|
||
|
'DOTALL',
|
||
|
'VERBOSE'):
|
||
|
if len(self.boxes) % 3 == 0:
|
||
|
frame = Frame(self.master)
|
||
|
frame.pack(fill=X)
|
||
|
self.frames.append(frame)
|
||
|
val = getattr(re, name)
|
||
|
var = IntVar()
|
||
|
box = Checkbutton(frame,
|
||
|
variable=var, text=name,
|
||
|
offvalue=0, onvalue=val,
|
||
|
command=self.recompile)
|
||
|
box.pack(side=LEFT)
|
||
|
self.boxes.append(box)
|
||
|
self.vars.append(var)
|
||
|
|
||
|
def getflags(self):
|
||
|
flags = 0
|
||
|
for var in self.vars:
|
||
|
flags = flags | var.get()
|
||
|
flags = flags
|
||
|
return flags
|
||
|
|
||
|
def recompile(self, event=None):
|
||
|
try:
|
||
|
self.compiled = re.compile(self.regexdisplay.get(),
|
||
|
self.getflags())
|
||
|
bg = self.promptdisplay['background']
|
||
|
self.statusdisplay.config(text="", background=bg)
|
||
|
except re.error as msg:
|
||
|
self.compiled = None
|
||
|
self.statusdisplay.config(
|
||
|
text="re.error: %s" % str(msg),
|
||
|
background="red")
|
||
|
self.reevaluate()
|
||
|
|
||
|
def reevaluate(self, event=None):
|
||
|
try:
|
||
|
self.stringdisplay.tag_remove("hit", "1.0", END)
|
||
|
except TclError:
|
||
|
pass
|
||
|
try:
|
||
|
self.stringdisplay.tag_remove("hit0", "1.0", END)
|
||
|
except TclError:
|
||
|
pass
|
||
|
self.grouplist.delete(0, END)
|
||
|
if not self.compiled:
|
||
|
return
|
||
|
self.stringdisplay.tag_configure("hit", background="yellow")
|
||
|
self.stringdisplay.tag_configure("hit0", background="orange")
|
||
|
text = self.stringdisplay.get("1.0", END)
|
||
|
last = 0
|
||
|
nmatches = 0
|
||
|
while last <= len(text):
|
||
|
m = self.compiled.search(text, last)
|
||
|
if m is None:
|
||
|
break
|
||
|
first, last = m.span()
|
||
|
if last == first:
|
||
|
last = first+1
|
||
|
tag = "hit0"
|
||
|
else:
|
||
|
tag = "hit"
|
||
|
pfirst = "1.0 + %d chars" % first
|
||
|
plast = "1.0 + %d chars" % last
|
||
|
self.stringdisplay.tag_add(tag, pfirst, plast)
|
||
|
if nmatches == 0:
|
||
|
self.stringdisplay.yview_pickplace(pfirst)
|
||
|
groups = list(m.groups())
|
||
|
groups.insert(0, m.group())
|
||
|
for i in range(len(groups)):
|
||
|
g = "%2d: %r" % (i, groups[i])
|
||
|
self.grouplist.insert(END, g)
|
||
|
nmatches = nmatches + 1
|
||
|
if self.showvar.get() == "first":
|
||
|
break
|
||
|
|
||
|
if nmatches == 0:
|
||
|
self.statusdisplay.config(text="(no match)",
|
||
|
background="yellow")
|
||
|
else:
|
||
|
self.statusdisplay.config(text="")
|
||
|
|
||
|
|
||
|
# Main function, run when invoked as a stand-alone Python program.
|
||
|
|
||
|
def main():
|
||
|
root = Tk()
|
||
|
demo = ReDemo(root)
|
||
|
root.protocol('WM_DELETE_WINDOW', root.quit)
|
||
|
root.mainloop()
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|