Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

1. Create a class using python which inputs text files, reads formatting options

ID: 3574760 • Letter: 1

Question

1. Create a class using python which inputs text files, reads formatting options containe within those text files and outputs the text were each ine is appropiatelly formatted as indicated.
The formatting command is:

.LM space: Each line following the command will be indented left spaces from the left-­hand margin. Note that this indentation must be included in the page width. If this command does not appear in the input file, then the value of left is 0 (zero).

Default behaviors:
- If no blank line exist at the end of the input file, then there must not be a blank lineat the end of the output file.
- The ".LM" command may appear at anyline of the input file.
- The margin is specified relative to the value of the current margin position. For example if the urrent margin is 10, then ".LM+5" will set the margin to 15, if margin is 7, then ".LM -2" will set the margin to 5 if margin is 7 then ".LM 10" will set the margin to 10.
- A ".LM" will never be immediately followed by another ".LM" command.
- Valid margins must be greater than or equal to 0 and less than or equal to the page widht minus 20. If a margin woul be negative after a ".LM" command, then the magin is set to zero.
- Linespaceing (.LS) will never have values greater than 2.
- There is no limit to the number of input line (Assume each line is no longer than 132 characters).

The class contructor will accept a file name and a list of strings, and the formatted output will be availale from the class instance via get_lines() method.If no text file is rovided then content of stdin will be formatted. If a list of strings is provided and no text file is provided then lines of the list provided as a parameter will be formatted. Must provide some error handling and Global/module scope variables are not permitted.

Explanation / Answer

Answer: Python program

import re

class InvalidOptionException(Exception):
"""
Thrown when someone puts in ?fmt 34, or ?pgwdth off, or anything else of the such. Note that this does not trigger on anything other then Ints and 'on'/'off', so ?fmt potato will be silently handled as normal input.
"""
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
  
class WordTooBigException(Exception):
"""
Thrown when a word is too big to fit on a line and we can't fit it anywhere else.
"""
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)

class seng265_formatter:
def __init__(self, inputlines=["?fmt on", "?pgwdth 30", "Hello there,", "beautiful world", "Here is a sentence with enough words to require some sort of word wrap. "], strict=False):
"""
Create and start parsing immediately so that it's ready when asked.
"""
self.opts = {
'fmt' : False, # Is formatting on or off?
'pgwdth' : 0, # The Maximum width of any given line. May change throughout processing.
'mrgn' : 0, # Desired page margin. Cannot be less then or equal to pgwdth-20
'strict' : strict # Defaults to false, determine if we should output errors.
}
self.state = {
'line_size' : 0, # The size of our current line so far.
'last_was_new' : False # Used to detect multiple carriage returns.
}
  
self.control_detect = re.compile(r"?(mrgn|fmt|pgwdth) (-|+)?(d+|on|off)s*$")
  
self.inputlines = inputlines # Map the input to somewhere we can access.
self.output = [] # We can store out output here.
self.parse_inputlines()
  
def parse_inputlines(self):
"""
Parse out each line and build the output
"""
for line in self.inputlines:
result = self.parse(line)
if result:
self.output.extend([result])
  
def parse(self, line):
"""
Detect a control sequence, if we don't find one, format the line as needed.
"""
detection = self.control_detect.match(line)
if detection:
match = detection.groups()
# ?fmt uses on|off
if match[0] == "fmt":
if match[2] == "on":
self.opts['fmt'] = True
elif match[2] == "off":
self.opts['fmt'] = False
elif self.opts['strict']:
print match
raise InvalidOptionException("?fmt called with a non on/off value. Line: " + line)
# Otherwise we'll do operator based settings
elif match[1] == "+":
try:
self.opts[match[0]] += int(match[2])
except ValueError:
if self.opts['strict']:
raise ValueError("Passed an invalid value after the + sign, most specifically, you passed on/off to a non-?fmt sequence. Line: " + line)
elif match[1] == "-":
try:
self.opts[match[0]] -= int(match[2])
except ValueError:
if self.opts['strict']:
raise ValueError("Passed an invalid value after the - sign, most specifically, you passed on/off to a non-?fmt sequence. Line: " + line)
else:
try:
self.opts[match[0]] = int(match[2])
except ValueError:
if self.opts['strict']:
raise ValueError("Passed an invalid value after the control sequence, most specifically, you passed on/off to a non-?fmt sequence. Line: " + line)
# Verify after each option change that the margins and pgwdths fit spec.
if match[0] == "pgwdth":
self.opts["fmt"] = True
if self.opts['mrgn'] < 0:
if self.opts['strict']:
raise ValueError("The margins were less then 0, this is against spec. Line: " + line + ", Margin: " + str(self.opts['mrgn']) + ", Page Width: " + str(self.opts['pgwdth']))
self.opts['mrgn'] = 0
if self.opts['mrgn'] > self.opts['pgwdth'] - 20:
self.opts['mrgn'] = self.opts['pgwdth'] - 20
if self.opts['mrgn'] < 0:
self.opts['mrgn'] = 0
if self.opts['strict'] and self.opts['pgwdth'] > 20:
raise ValueError("The margins were greater then pgwdth - 20, this is against spec. Line: " + line)


# Since we got a match, we need to get rid of this string.
line = None
  
# Output the line
if self.opts['fmt'] and line:
# Special case for empty lines.
split = line.split()
if split == []:
self.state['line_size'] = 0
if self.state['last_was_new']:
return ' '
else:
self.state['last_was_new'] = True
return ' '
self.state['last_was_new'] = False
  
# Do we need a margin? (Is this a new line?)
if self.state['line_size'] == 0:
out = "".join( [" " for i in range(self.opts['mrgn']) ] )
self.state['line_size'] = self.opts['mrgn']
else:
out = ""
  
# Gradually add each word, making sure we're not going over the pgwdth
for word in split:
# Is the word longer then the max line length?
if self.opts['strict'] and len(word) > self.opts['pgwdth'] - self.opts['mrgn']:
raise WordTooBigException("Your word size was too big to fit on a given line. Word: " + word)
# Do we need a new line?
if self.state['line_size'] + len(word) >= self.opts['pgwdth']:
margin = "".join( [" " for i in range(self.opts['mrgn']) ] )
out = out + ' ' + margin
self.state['line_size'] = self.opts['mrgn']
# Otherwise, add a space
elif self.state['line_size'] != self.opts['mrgn']:
self.state['line_size'] += 1
out = out + ' '
# Concatenate
out = out + word
self.state['line_size'] += len(word)
return out
else:
return line
  
  
def get_lines(self):
"""
Return the result of processing.
"""
return self.output
  
if __name__ == "__main__":
formatter = seng265_formatter()
lines = formatter.get_lines()
print ' '.join(lines)

output: