Word wrap function / algorithm for wrapping text using proportional (versus fixed-width) fonts.
text
: a string of text to wrap
width
: the width in pixels to wrap to
extent_func
: a function that returns a (w, h) tuple given any string, to
specify the size (text extent) of the string when rendered.
the algorithm only uses the width.
Returns a list of strings, one for each line after wrapping.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import re
def word_wrap(text, width, extent_func):
'''
Word wrap function / algorithm for wrapping text using proportional (versus
fixed-width) fonts.
`text`: a string of text to wrap
`width`: the width in pixels to wrap to
`extent_func`: a function that returns a (w, h) tuple given any string, to
specify the size (text extent) of the string when rendered.
the algorithm only uses the width.
Returns a list of strings, one for each line after wrapping.
'''
lines = []
pattern = re.compile(r'(\s+)')
lookup = dict((c, extent_func(c)[0]) for c in set(text))
for line in text.splitlines():
tokens = pattern.split(line)
tokens.append('')
widths = [sum(lookup[c] for c in token) for token in tokens]
start, total = 0, 0
for index in xrange(0, len(tokens), 2):
if total + widths[index] > width:
end = index + 2 if index == start else index
lines.append(''.join(tokens[start:end]))
start, total = end, 0
if end == index + 2:
continue
total += widths[index] + widths[index + 1]
if start < len(tokens):
lines.append(''.join(tokens[start:]))
lines = [line.strip() for line in lines]
return lines or ['']
if __name__ == '__main__':
text = (
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do '
'eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n'
'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris '
'nisi ut aliquip ex ea commodo consequat.\n\n'
'Duis aute irure dolor in reprehenderit in voluptate velit esse '
'cillum dolore eu fugiat nulla pariatur.\n\n'
'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui '
'officia deserunt mollit anim id est laborum.'
)
# dummy extent function behaves like a fixed-width font
def extent_func(text):
return (1, 0)
# wrap to 80 columns
lines = word_wrap(text, 80, extent_func)
for line in lines:
print line
|
Python has a built-in module for word wrapping fixed-width text. There aren't many solutions out there for wrapping proportional fonts where the characters vary in width. This algorithm is such a solution.