Below is a script called grepper.py that I wrote to your
specifications. You'll notice that in the second line of the script, I
assign a string value to the variable read_from_file. This value,
which you should feel free to modify, is the name of the file that
grepper.py will initially attempt to open.
At launch, the top pane of the application window shows the initial
file name. In the upper right corner is the Open button, which you can
use at any time to select a new file.
The middle pane consists of a box where you can enter a search string.
This string will be interpreted as a case-insensitive regular
expression and applied to every line of the opened file. Don't worry
if you're not familiar with the special syntax of regular expressions;
plain strings such as "repair" and "body shop" will be interpreted
literally.
As soon as you press the Enter key, grepper.py starts searching
through the contents of the file. This may take a while in the case of
novels and other long documents. Note that if the search string is
empty, all lines will be displayed.
The bottom pane shows the results of your search. If grepper.py was
unable to open the specified file, it displays an error message.
Otherwise, those lines that matched the regular expression are
displayed, along with the respective line numbers in gray, and with
every matching substring in red.
Pressing the Escape key causes the application to quit.
Triple-clicking in the search box selects the entire string; then, you
can use Backspace to immediately clear the box, or just start typing
to replace the string.
Code follows. As you know, Python is sensitive to indentation, so I've
made the lines extra-short in order to avoid spurious line breaks.
#==begin grepper.py
read_from_file = 'C:\My Documents\phone.txt'
import sys, os, string, re
from Tkinter import *
from tkFileDialog import *
class Grepper:
def __init__(self):
self.fname = read_from_file
self.root = Tk()
self.root.title('grepper.py')
self.root.bind('<KeyPress>', self.key_press)
root_frame = Frame(self.root, bg='white')
root_frame.pack(expand=YES, fill=BOTH)
top_frame = Frame(root_frame, bg='white')
top_frame.pack(side=TOP, expand=NO, fill=X)
self.fname_label = Label(top_frame, text=self.fname,
fg='dark blue', bg='white',
font=('helvetica', 12, 'normal'))
self.fname_label.pack(side=LEFT, expand=YES, fill=X)
self.open_button = Button(top_frame, text='Open',
command=self.open, bg='antiquewhite',
font=('helvetica', 12, 'bold'))
self.open_button.pack(side=RIGHT, expand=NO)
regex_frame = Frame(root_frame, bg='white')
self.regex_entry = Entry(regex_frame, width = 60,
bg='cornsilk', fg='dark red',
font=('helvetica', 12, 'bold'))
self.regex_entry.pack(side=LEFT, expand=YES, fill=X)
self.regex_entry.bind('<KeyPress>', self.key_press)
text_frame = Frame(root_frame, bg='white')
text_frame.pack(side=BOTTOM, expand=YES, fill=Y)
regex_frame.pack(side=BOTTOM, expand=NO, fill=X)
self.lines_text = Text(text_frame, fg='black', bg='white',
width=80, height=20, font=('courier', 10, 'normal'))
self.lines_text.pack(side=LEFT, expand=YES, fill=BOTH)
self.lines_y_scrollbar = Scrollbar(text_frame,
orient=VERTICAL, command=self.lines_text.yview)
self.lines_text.configure(
yscrollcommand=self.lines_y_scrollbar.set)
self.lines_y_scrollbar.pack(side=RIGHT, expand=YES, fill=Y)
self.lines_text.tag_config('match', foreground='dark red',
background='white')
self.lines_text.tag_config('bold', font=('helvetica', 12,
'bold'))
self.lines_text.tag_config('number', foreground='gray')
self.lines_text.tag_config('error', foreground='red')
self.lines_text.configure(state=DISABLED)
self.ctrlRE = re.compile('\\r')
self.open(0)
self.grep()
self.root.mainloop()
def key_press(self, event):
keysym = event.keysym.lower()
if keysym in ['escape']:
self.root.quit()
elif keysym in ['enter', 'return']:
self.grep()
def open(self, ask=1):
if ask:
self.fname = askopenfilename(initialdir=self.open_dir)
self.open_dir = os.path.split(self.fname)[0]
self.fname_label.configure(text=self.fname)
if os.path.isfile(self.fname):
self.lines = open(self.fname).readlines()
self.grep()
def clear(self):
self.regex_entry.configure(text='')
self.grep()
def grep(self):
self.lines_text.configure(state=NORMAL)
self.lines_text.delete('1.0', END)
if not os.path.isfile(self.fname):
self.lines_text.insert(END, 'Error: ', 'error',
self.fname, 'bold', ' is not a file', 'error')
self.lines_text.configure(state=DISABLED)
return
self.lineRE = re.compile(self.regex_entry.get(),
re.IGNORECASE)
blank = 0
if not self.regex_entry.get().split():
blank = 1
i = 0
for line in self.lines:
i = i+1
line = self.ctrlRE.sub('', line)
findall = self.lineRE.findall(line)
if not findall:
continue
self.lines_text.insert(END, '%4d: ' % i, 'number')
if blank:
self.lines_text.insert(END, line)
continue
split = self.lineRE.split(line)
for j in range(len(findall)):
self.lines_text.insert(END, split[j])
self.lines_text.insert(END, findall[j], 'match')
self.lines_text.insert(END, split[-1])
self.lines_text.configure(state=DISABLED)
Grepper()
#==end grepper.py
I tested this script using python-2.2.1 and tk-8.3.3 under Linux, but
it should work just fine in Windows. The only possible exception I
foresee is that the rules of your window manager are slightly
different from mine. For example, you might have to double-click and
not triple-click in the search box in order to select the entire
string.
If you have trouble running the script, please let me know so that I
have a chance to meet your needs before you assign a rating.
Cheers,
leapinglizard |