5

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.

Community
  • 1
  • 1
secarica
  • 597
  • 5
  • 18

3 Answers3

17

Use the textwrap module:

>>> textwrap.wrap("This text will display on 3 LCD lines", 20)
['This text will', 'display on 3 LCD', 'lines']
Dan D.
  • 73,243
  • 15
  • 104
  • 123
  • While I actually used this solution, I still have a dilemma as expressed in my other comment related to the [darkryder solution](http://stackoverflow.com/a/32295642/3549017). – secarica Aug 30 '15 at 12:17
2
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.

Community
  • 1
  • 1
darkryder
  • 792
  • 1
  • 8
  • 25
  • 1
    Regarding "Always use libraries instead of making feeble attempts to reinvent the wheel", I am a bit in doubt here: in terms of overall efficiency when running the program, given a particular case where a function is only required once in a relatively long (>1000 lines) overall program code, is it ok to just import one (more) library in order to simplify few lines of my code (like `textwrap` in Dan D. answer), or is it better to complicate a bit my local code in order to avoid importing a library? So just then, not if the function call is required more than once (assuming this is foreseeable). – secarica Aug 30 '15 at 11:58
  • 1
    When the standard library solves exactly your need in a single stroke, go for it. It will be well tested, used by other people in the world, will handle obscure corner cases. But the best thing is that the meaning will be so much clearer, for a future maintainer and for yourself. – Francesco Aug 30 '15 at 20:25
0

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!
Chaker
  • 1,197
  • 9
  • 22