I wrote a bit of code that takes a file, justifies the text and writes to another file.
It uses a DP approach to minimise a badness metric, which is the amount of undershoot of the line length, cubed (see my answer below, the badness function isn't quite right if there is an overshoot, the badness should be inf
- I believe this is how LaTeX justifies its text).
I encapsulated it in a class
(which is the bit I'm least confident about). Be careful running it on big files, because I think it's got a pretty nasty complexity (\$O(n^2)\$ maybe).
class justifyText:
def __init__(self, inFileName, outFileName, pageWidth):
with open(inFileName, "r") as fp:
self.words = [word for line in fp for word in line.split()]
self.outFileName = outFileName
self.pageWidth = pageWidth
self.memo = {}
self.breakPointTrack = {}
self.n = len(self.words)
def badness(self, i, j):
totalWidth = 0;
for word in self.words[i:j]:
totalWidth += len(word)
return abs((self.pageWidth - totalWidth)**3)
def minBadness(self, i):
if i in self.memo:
return self.memo[i]
if i == self.n:
f = 0
j_min = self.n
else:
f = None
for j in range(i + 1, self.n + 1):
temp = self.minBadness(j) + self.badness(i, j)
if (f is None) or (temp < f):
f = temp
j_min = j
self.memo[i] = f
self.breakPointTrack[i] = j_min
return f
def justify(self):
self.minBadness(0)
fOut = open(self.outFileName, "w")
brk = 0
while brk < self.n:
start = brk
brk = self.breakPointTrack[brk]
line = " ".join(self.words[start:brk]) + "\n"
fOut.write(line)
fOut.close()
test = justifyText("test.txt", "out.txt", 80)
test.justify()
Is this a standard way to implement a DP program? I know that global variables are evil, so I was mainly trying to avoid my memo etc. being that.
abs()
call in yourbadness()
function that is mentioned in the answer. If you have found a bug, you can write an answer to your own question explaining what the bug is. \$\endgroup\$