All pastes #28011 Raw Edit

Python

public python v1 · immutable
#28011 ·published 2005-11-08 17:57 UTC
rendered paste body
import sysclass TokenException(Exception):	passclass ParseException(Exception):	pass	class Tokenizer:	def __init__(self, f):		"""		Init the tokenizer on the given file, may throw an exception.		"""		self.i = 0		# Read the file, coud be streamed as well		self.f = f		self.data = file(f).read()				self.state = "linestart"			def get_next_token(self):		"""		Returns the next token in the file.		A token is one of:		< = > name				Returns None when the end of file is reached and beyond		"""		while self.i < len(self.data):			char = self.data[self.i]			# Skip leading spaces (which are really trailing spaces after a token			# Newline is important so special case it			if char.isspace() and not char == "\n":				self.i += 1				continue						if self.state == "linestart" and char == "#":				# Eat all the comment line				while self.i < len(self.data) and self.data[self.i] != "\n":					self.i += 1				self.i += 1 #position on first char after newline				continue						# At this point, we can only have a token, read it, and return it			# The method updates the self.i to point to the new char to read next			next_token = self.read_token()			# Wait ! We got a newline here, so back to start again..			if next_token == "\n":				self.state = "linestart"				continue							return next_token		def read_token(self):		"""		Return the token, self.i must point to the first char in this token.		self.i is updated to point just after the returned token		Returned token is one of:		< = > \n name		"""		char = self.data[self.i]				if char == "<" or char == "=" or char == ">" or char == "\n":			self.i += 1			return char				elif char == "\"":			# Here we assume proper quoting			closing = self.data[self.i+1:].find("\"")			if closing == -1:				raise TokenException("Couldn't find a proper closing quote in %s" % self.f)						token = self.data[self.i+1:self.i+1+closing]			self.i += closing+2 #Next char is just *after* the closing "			return token				else:			# Token can just be a string now..			token = ""			# We eat all chars until one of "=<>" or whitespace is found			while self.i < len(self.data) and not self.data[self.i].isspace() and not self.data[self.i] in "=><":				token += self.data[self.i]				self.i += 1							return tokenclass MozillaParser:	def __init__(self, f):		"""		Init the parse, no exception here		"""		self.f = f		self.infos = {			"search": {},			"input": {},		}			def parse(self):		"""		"""		tokenizer = Tokenizer(self.f)		n = state = None				# We load the two first tokens, whch should be ["<", "search"]		tokens = [tokenizer.get_next_token(), tokenizer.get_next_token()]		while tokens[0] != None:			# Retreive the next state, the number of tokens to read next, and any discarded tokens			# by the handler, which should be handled on next iteration			state, n, rest = self._handle_token(state, tokens)			# If n == None, we finished parsing			if n == None:				break						# Read the requested number of tokens, but count the ones that were rejected first			tokens = rest			for i in range(n - len(rest)):				tokens.append(tokenizer.get_next_token())		def _handle_token(self, state, tokens):		if state == None and (tokens == ["<", "search"] or tokens == ["<", "SEARCH"]):			return "search", 3, []		elif state == None:			raise ParseException("File %s does not begin with <search" % self.f)				# Read key=value pairs and store them in the infos["search"] dict		if state == "search" and tokens[1] == "=":			self.infos["search"][tokens[0]] = tokens[2]			return "search", 3, []				# We reached the end of <Search tag, now in theory come the <input> tags		if state == "search" or state == "anotherinput" and tokens == [">", "<", "input"]:			return "input", 6, []		elif state == "search":			raise ParseException("Expecting <input after <search section in file %s" % self.f)				# This parses the <input fields, taking each time 6 tokens		# First triplet is name=value, second triplet is value=val		# Special case for lone "user" second triplets, and store that in infos["input"] dict		if state == "input" and tokens[1] == "=":			if tokens[3] == "user":				self.infos["input"][tokens[2]] = "%s"				if tokens[4] != "=":					return "anotherinput", 3, tokens[4:]			else:				self.infos["input"][tokens[2]] = tokens[5]			return "anotherinput", 3, []				# Here we stop processing, cause we are no longer in <input sections, and what comes after isn't interesting		return None, None, Nonefor f in sys.argv[1:]:	moz = MozillaParser(f)	print "Reading file: ", f	moz.parse()	print "Search:"	for key, value in moz.infos["search"].items():		print "\t", key, ":", value	print "Input:"	for key, value in moz.infos["input"].items():		print "\t", key, ":", value