I've written a set of classes that wrap a file or a list. The heart of
the matter (at least for what you're interested in doing) is the
"current()" method, which allows you to specify an offset, which
allows you to lookahead or backward.
#-------------------------------------------------------------
#
# class: InputList
#
#-------------------------------------------------------------
class InputList:
"""This class holds a list of strings.
The list supports file-like operations.
Subclasses can have the __init__() method over-ridden,
in order to be loaded from files.
"""
def __init__(self, aList):
"""the aList argument should be a list of strings.
"""
self.items = aList
self.reset()
return
def __len__(self):
return len(self.items)
def reset(self):
# removed and converted to a method --- self.last_index() =
len(self.items) - 1
self.index = -1
return
def last_index(self):
return len(self.items) - 1
def getnext(self):
self.index = self.index + 1
return self.current()
def get(self):
return self.getnext()
def current(self, lookahead_count = 0,
value_to_be_returned_if_past_end=""):
"""return the item at the current position, unless we are past the
last item,
in which case return value_to_be_returned_if_past_end.
"""
lookahead_index = self.index + lookahead_count
if lookahead_index > self.last_index(): return
value_to_be_returned_if_past_end
else: return self.items[lookahead_index]
def eof(self,lookahead_count = 0):
"""look ahead lookahead_count items, and see if that position is
past
the end of the file. Return 1 if it is, otherwise return 0.
"""
lookahead_index = self.index + lookahead_count
if lookahead_index > self.last_index(): return 1
else: return 0
def more(self):
"""The opposite of eof. A convenience feature.
"""
if self.eof() == 0: return 1
return 0
def getIndex(self):
return self.index
def current_count(self):
return self.index + 1
def sortInsensitive(self):
"""A case-insensitive sort, in place.
Uppercase A sorts before lower-case A.
"""
temp = []
for item in self.items:
temp.append((item.upper(), item))
temp.sort()
self.items = []
for item in temp:
self.items.append(item[1])
del temp
return None
def size(self):
return len(self.items)
def remove(self, comment_indicator = None):
""" Remove lines from the list
if comment_indicator = None, remove all blank lines.
Otherwise, remove all lines that have comment_indicator in column 1.
"""
indexes = range(len(self.items))
indexes.reverse()
if comment_indicator != None: cLength = len(comment_indicator)
for i in indexes:
if comment_indicator == None:
if self.items.strip() == "": del self.items
else:
if self.items.strip()[:cLength] == comment_indicator: del
self.items
def remove_trailing(self, comment_indicator = None):
""" Remove lines from the list
Like remove(), but works from the trailing end of the list, and
works
only as long as it finds a line that can be removed.
if comment_indicator = None, remove blank lines.
Otherwise, remove lines that have comment_indicator in column 1.
"""
indexes = range(len(self.items))
indexes.reverse()
if comment_indicator != None: cLength = len(comment_indicator)
for i in indexes:
if comment_indicator == None:
if self.items.strip() == "": del self.items
else: break
else:
if self.items.strip()[:cLength] == comment_indicator: del
self.items
else: break
def remove_leading(self, comment_indicator = None):
""" Remove lines from the list
Like remove(), but works from the front end of the list, and works
only as long as it finds a line that can be removed.
if comment_indicator = None, remove blank lines.
Otherwise, remove lines that have comment_indicator in column 1.
"""
indexes = range(len(self.items))
indexes_to_remove = []
if comment_indicator != None: cLength = len(comment_indicator)
for i in indexes:
if comment_indicator == None:
if self.items.strip() == "": indexes_to_remove.append(i)
else: break
else:
if self.items.strip()[:cLength] == comment_indicator:
indexes_to_remove.append(i)
else: break
if len(indexes_to_remove) > 0:
indexes_to_remove.reverse()
for i in indexes_to_remove:
del self.items
def close(self):
return
def strip(self):
# strip trailing whitespace (including newlines) from each line
i = 0
while i < len(self.items):
self.items = string.rstrip(self.items)
i = i + 1
#-------------------------------------------------------------
# end of class: InputList
#-------------------------------------------------------------
#-------------------------------------------------------------
#class: InputFileOrStream
#-------------------------------------------------------------
class InputFileOrStream(InputList):
def delete(self):
if f_exists(self.myFilename): f_delete(self.myFilename)
def filename(self):
return self.myFilename
#-------------------------------------------------------------
# end of class: InputFileOrStream
#-------------------------------------------------------------
#-------------------------------------------------------------
#class: InputFile
#-------------------------------------------------------------
class InputFile(InputFileOrStream):
"""Read a file as a list of lines.
"""
"""This class is an abstract class for InputFile and Input Stream.
_______ How to use it: code example ___________
import fpx
infile = fpx.InputFile(infile_name)
#or infile = fpx.InputStream(infile_name)
infile.getnext()
while not infile.eof():
print infile.current_count(),infile.current()
infile.getnext()
print "Processed", infile.total_count(), "lines in file",
infile.filename()
"""
def __init__(self, name):
"""the name argument should be a text string containing
the name of the file to be read in.
"""
# open the file and read it into a list, and close it
self.myFilename = os.path.normcase(name)
file = open(self.myFilename, "r")
self.items = file.readlines()
file.close()
self.strip()
self.reset()
def linein(self):
"""A method for REXX compatibility.
"""
return self.getnext()
def getline(self):
return self.getnext()
#-------------------------------------------------------------
# end of class: InputFile
#-------------------------------------------------------------
#-------------------------------------------------------------
# class: InputStream
#-------------------------------------------------------------
class InputStream(InputFileOrStream):
"""Read a file as a list of characters.
"""
def __init__(self, name):
"""The name argument should be a text string containing
the name of the file to be read in.
"""
# open the file and read it into a list, and close it
self.myFilename = os.path.normcase(name)
file = open(self.myFilename, "r")
self.items = file.read()
file.close()
self.myLineIndex = -1
self.myCharIndexInLine = -1
self.reset()
return
def charin(self):
"""Method for REXX compatibility.
"""
return self.getchar()
def getchar(self):
if self.myLineIndex == -1:
self.myLineIndex = 0
self.myCharIndexInLine = 0
else:
if self.current() == "\n":
self.myLineIndex += 1
self.myCharIndexInLine = 0
else:
self.myCharIndexInLine += 1
return self.getnext()
#-------------------------------------------------------------
# end of class: InputStream
#-------------------------------------------------------------