ungetch in Python

Stephen Ferg steve at ferg.org
Sun Dec 28 18:30:43 EST 2003


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[i].strip() == "": del self.items[i]
			else:
				if self.items[i].strip()[:cLength] == comment_indicator: del
self.items[i]


	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[i].strip() == "": del self.items[i]
				else: break
			else:
				if self.items[i].strip()[:cLength] == comment_indicator: del
self.items[i]
				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[i].strip() == "": indexes_to_remove.append(i)
				else: break
			else:
				if self.items[i].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[i]


	def close(self):
		return

	def strip(self):
		# strip trailing whitespace (including newlines) from each line
		i = 0
		while i < len(self.items):
			self.items[i] = string.rstrip(self.items[i])
			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
#-------------------------------------------------------------




More information about the Python-list mailing list