secarica
secarica

Reputation: 619

chunk string in Python without breaking words

I have this code which is meant to display some text on a 20x2 LCD display:

#!/usr/bin/python

LCDCHARS = 20
LCDLINES = 2

def WriteLCD(text_per_LCD):
    chunked = (text_per_LCD[i:LCDCHARS+i] for i in range (0, len(text_per_LCD), LCDCHARS))
    count_l = 0
    for text_per_line in chunked:
        # print will be replaced by actual LCD call
        print (text_per_line)
        count_l += 1
        if count_l >= LCDLINES:
            # agree to lose any extra lines
            break

WriteLCD("This text will display on %s LCD lines" % (LCDLINES))

The example string will output

This text will displ
ay on 2 LCD lines

What should I do to split the string without breaking the words? This even if the second line becomes longer and goes out of display.

I read a similar question on javascript section and another one in ruby section, but I was not able to translate the given answers into my Python case.

Upvotes: 5

Views: 2536

Answers (3)

darkryder
darkryder

Reputation: 832

YOUR_STRING = "This text will display on 10 LCD lines"
CHAR_LIMIT = 25 # anything

First off, let's start with finding out the breakpoints(spaces in your case).

Let's use the function from https://stackoverflow.com/a/11122355/2851353

def find(s, ch):
    return [i for i, ltr in enumerate(s) if ltr == ch]

breakpoints = find(YOUR_STRING, " ")
# [4, 9, 14, 22, 25, 28, 32]

Now, we find what's the index of the word till where we can safely split the sentence.

Let's find another function from: https://stackoverflow.com/a/2236956/2851353

def element_index_partition(points, breakpoint):
    return [ n for n,i in enumerate(points) if i>breakpoint ][0]

best = element_index_partition(breakpoints, CHAR_LIMIT)

Now, we just need to split and rejoin the string.

# We won't go till `best` (inclusive) because the function returns the next index of the partition
first_str = " ".join(YOUR_STRING.split(" ")[:best])
last_str =  " ".join(YOUR_STRING.split(" ")[best:])

EDIT After seeing the answer given by Dan D., use that answer. Always use libraries instead of making feeble attempts to reinvent the wheel. Always.

Upvotes: 2

Chaker
Chaker

Reputation: 1207

Using generator:

LCDCHARS = 20
LINE = "This text will display on 2 LCD lines No more!"
LCDLINES = 2

def split_line(line):
    words = line.split()                                                                                                                               
    l = ""
    # Number of lines printed
    i = 0
    for word in words:
        if i < LCDLINES - 1 and len(word)+ len(l) > LCDCHARS:
            yield l.strip()
            l = word
            i += 1
        else:
            l+= " " + word
    yield l.strip()

for line in split_line(LINE):
    print line

Output:

This text will
display on 2 LCD lines No more!

Upvotes: 0

Dan D.
Dan D.

Reputation: 74655

Use the textwrap module:

>>> textwrap.wrap("This text will display on 3 LCD lines", 20)
['This text will', 'display on 3 LCD', 'lines']

Upvotes: 17

Related Questions