Formatting a string to be a columned block of text

Discussion in 'Python' started by Leon, Dec 26, 2006.

  1. Leon

    Leon Guest

    Hi,

    I'm creating a python script that can take a string and print it to the
    screen as a simple multi-columned block of mono-spaced, unhyphenated
    text based on a specified character width and line hight for a column.
    For example, if i fed the script an an essay, it would format the text
    like a newspaper on the screen. Text processing is very new to me, any
    ideas on how I could achieve a multi-columned text formatter. Are there
    any libraries that already do this?

    Thanks and happy holidays!
    Leon
     
    Leon, Dec 26, 2006
    #1
    1. Advertising

  2. Leon

    placid Guest

    Leon wrote:
    > Hi,
    >
    > I'm creating a python script that can take a string and print it to the
    > screen as a simple multi-columned block of mono-spaced, unhyphenated
    > text based on a specified character width and line hight for a column.
    > For example, if i fed the script an an essay, it would format the text
    > like a newspaper on the screen. Text processing is very new to me, any
    > ideas on how I could achieve a multi-columned text formatter. Are there
    > any libraries that already do this?
    >
    > Thanks and happy holidays!
    > Leon


    I did something similar, read in text file format it to 79 characters
    and print it out to a multiple images of 480x272 so i could read them
    on my PSP. Anyway the code to handle the formatting (even though this
    is one column of 78 characters with one character space from the top
    and bottom, and sides)

    corpus = open("essay.txt","r")

    wordcount = 0
    pctline = ""
    pctlines = [

    for line in corpus.readlines():
    # i dont need the newline character as it will be printed onto
    images
    line = line[:-1]

    # i want individual words where each word is separated by a space
    character
    words = line.split(" ")

    for word in words:
    if wordcount + len(word) + 1 < 78:
    wordcount = wordcount + len(word) + 1
    pctline = pctline + word + " "
    else:
    wordcount = len(word)

    pctlines.append(pctline)
    pctline = None
    pctline = word + " "

    corpus.close()

    what it does is keeps a list of words and iterate through it and see if
    the length of that word and one space character and the line doesn't
    exceed 78, if it doesnt then add it to the pctlines, add the count to
    the wordcount + 1. If it does then we have one line either 78
    characters long or less and add it to pctlines which is a list of all
    the lines.

    Hope this helps.
    Cheers
     
    placid, Dec 26, 2006
    #2
    1. Advertising

  3. Leon

    Paul McGuire Guest

    "Leon" <> wrote in message
    news:...
    > Hi,
    >
    > I'm creating a python script that can take a string and print it to the
    > screen as a simple multi-columned block of mono-spaced, unhyphenated
    > text based on a specified character width and line hight for a column.
    > For example, if i fed the script an an essay, it would format the text
    > like a newspaper on the screen. Text processing is very new to me, any
    > ideas on how I could achieve a multi-columned text formatter. Are there
    > any libraries that already do this?
    >
    > Thanks and happy holidays!
    > Leon
    >

    Check out the textwrap module, new in 2.3. Here is code to do one- and
    two-column output.

    -- Paul


    gettysburgAddress = """Four score and seven years ago our fathers brought
    forth on this continent, a new nation, conceived in Liberty, and dedicated
    to the proposition that all men are created equal.
    Now we are engaged in a great civil war, testing whether that nation, or any
    nation so conceived and so dedicated, can long endure. We are met on a great
    battle-field of that war. We have come to dedicate a portion of that field,
    as a final resting place for those who here gave their lives that that
    nation might live. It is altogether fitting and proper that we should do
    this.
    But, in a larger sense, we can not dedicate -- we can not consecrate -- we
    can not hallow -- this ground. The brave men, living and dead, who struggled
    here, have consecrated it, far above our poor power to add or detract. The
    world will little note, nor long remember what we say here, but it can never
    forget what they did here. It is for us the living, rather, to be dedicated
    here to the unfinished work which they who fought here have thus far so
    nobly advanced. It is rather for us to be here dedicated to the great task
    remaining before us -- that from these honored dead we take increased
    devotion to that cause for which they gave the last full measure of
    devotion -- that we here highly resolve that these dead shall not have died
    in vain -- that this nation, under God, shall have a new birth of freedom --
    and that government of the people, by the people, for the people, shall not
    perish from the earth.
    """.split('\n')

    import textwrap

    # wrap text at 50 characters
    for line in gettysburgAddress:
    print "\n".join( textwrap.wrap(line,50) )
    print

    # create two columns of text
    wrappedLines = sum([ textwrap.wrap(line,35) + ['']
    for line in gettysburgAddress ],[])[:-1]
    numLines = len(wrappedLines)
    halfway = numLines/2
    twoCol = [ "%-38s%s" % pair for pair in
    zip(wrappedLines[:halfway],wrappedLines[halfway:]) ]
    print "\n".join(twoCol)
     
    Paul McGuire, Dec 26, 2006
    #3
  4. Leon

    Dave Borne Guest

    On 26 Dec 2006 04:14:27 -0800, Leon <> wrote:
    > I'm creating a python script that can take a string and print it to the
    > screen as a simple multi-columned block of mono-spaced, unhyphenated
    > text based on a specified character width and line hight for a column.


    Hi, Leon,
    For putting the columns together zip is your friend. Let me lay out an example:

    # get your text and strip the newlines:
    testdata = file('something').read().replace('\n','')
    # set some parameters (these are arbitrary, pick what you need)::
    colwidth = 35
    colheight = 20
    numcol = 2
    rowperpage = colheight * numcol
    # first split into lines (this ignores word boundaries
    # you might want to use somehting more like placid posted for this)
    data1 = [testdata[x:x+colwidth] for x in range(0,len(testdata),colwidth)]
    # next pad out the list to be an even number of rows - this will give
    # a short final column. If you want them balanced you're on your own ;)
    data1.extend(['' for x in range(rowsperpage - len(data1) % rowsperpage)])
    # then split up the list based on the column length you want:
    data2 = [data1[x:x+colheight] for x in range(0,len(data1),colheight)]
    # then use zip to transpose the lists into columns
    pages = [zip(*data2[x:x+numcol]) for x in range(0,len(data2),numcol)]
    # finally unpack this data with some loops and print:
    for page in pages:
    for line in page:
    for column in line:
    print ' %s ' % column, #<- note the comma keeps newlines out
    print '\n'
    print '\f'


    -dave
     
    Dave Borne, Dec 26, 2006
    #4
  5. Leon

    Dave Borne Guest

    Thanks, Paul. I didn't know about textwrap, that's neat.

    Leon,
    so in my example change
    > data1= [testdata[x:x+colwidth] for x in range(0,len(testdata),colwidth)]

    to
    > data1 = textwrap.wrap(testdata,colwidth)
    > data1 = [x.ljust(colwidth) for x in data1]


    oh and I made a mistake that double spaces it. the "print '\n'"
    line needs to be either
    print ''
    or
    print '\n',
    (with a comma)

    -dave
     
    Dave Borne, Dec 26, 2006
    #5
  6. Leon

    Paul McGuire Guest

    "Paul McGuire" <._bogus_.com> wrote in message
    news:459136c5$0$16985$...
    >
    > gettysburgAddress = """Four score and seven years ago...

    <snip>

    By the way, this variable contains only 3 (very long) lines of text, one for
    each paragraph. (Not immediately obvious after Usenet wraps the text.)

    -- Paul
     
    Paul McGuire, Dec 26, 2006
    #6
  7. Leon

    Duncan Booth Guest

    "Paul McGuire" <._bogus_.com> wrote:
    > By the way, this variable contains only 3 (very long) lines of text,
    > one for each paragraph. (Not immediately obvious after Usenet wraps
    > the text.)


    Usenet doesn't wrap text, all it has is a convention which suggests that
    people posting to usenet should wrap their text at 72 characters. Your
    newsreader probably wrapped the text for you when you were posting, but
    for deliberately long lines many newsreaders will have an option
    somewhere to turn off the text wrapping (and the reader probably also
    has to turn off text wrapping when they read it).

    For source code where you want long unwrapped strings you would have
    been better to do the text wrapping in an editor first and use backslash
    line continuations.

    e.g.
    gettysburgAddress = """\
    Four score and seven years ago our fathers brought forth on this \
    continent, a new nation, conceived in Liberty, and dedicated to the \
    proposition that all men are created equal.
    Now we are engaged in a great civil war, testing whether that nation, \
    or any nation so conceived and so dedicated, can long endure. We are \
    met on a great battle-field of that war. We have come to dedicate a \
    portion of that field, as a final resting place for those who here \
    gave their lives that that nation might live. It is altogether fitting \
    and proper that we should do this.
    But, in a larger sense, we can not dedicate -- we can not consecrate \
    -- we can not hallow -- this ground. The brave men, living and dead, \
    who struggled here, have consecrated it, far above our poor power to \
    add or detract. The world will little note, nor long remember what we \
    say here, but it can never forget what they did here. It is for us the \
    living, rather, to be dedicated here to the unfinished work which they \
    who fought here have thus far so nobly advanced. It is rather for us \
    to be here dedicated to the great task remaining before us -- that \
    from these honored dead we take increased devotion to that cause for \
    which they gave the last full measure of devotion -- that we here \
    highly resolve that these dead shall not have died in vain -- that \
    this nation, under God, shall have a new birth of freedom -- and that \
    government of the people, by the people, for the people, shall not \
    perish from the earth.\
    """.split('\n')
     
    Duncan Booth, Dec 26, 2006
    #7
  8. Leon

    rzed Guest

    "Dave Borne" <> wrote in
    news::

    > Thanks, Paul. I didn't know about textwrap, that's neat.
    >
    > Leon,
    > so in my example change
    >> data1= [testdata[x:x+colwidth] for x in
    >> range(0,len(testdata),colwidth)]

    > to
    >> data1 = textwrap.wrap(testdata,colwidth)
    >> data1 = [x.ljust(colwidth) for x in data1]

    >
    > oh and I made a mistake that double spaces it. the "print '\n'"
    > line needs to be either
    > print ''
    > or
    > print '\n',
    > (with a comma)
    >


    The solutions so far serve up text that is split within the
    confines of the column width, but leave a "ragged right" margin,
    where the line lengths appear to differ. I had the impression that
    the OP wanted right-and-left justified text, such as would
    typically be found in a newspaper column. Here's a shot at doing
    that for fixed-width fonts. To use it, first split your lines as
    others have suggested, then print aline(line,colwid) for each line
    in your data.

    # aline - align text to fit in specified width
    # This module arbitrarily chooses to operate only on long-enough
    # lines, where "long-enough" is defined as 60% of the specified
    # width in this case.
    #
    def aline(line, wid):
    line = line.strip()
    lnlen = len(line)
    if wid > lnlen > wid*0.6:
    ls = line.split()
    diff = wid - lnlen
    #nspaces = len(ls)-1
    eix = 1
    bix = 1
    while diff > 0: # and nspaces > 0:
    if len(ls[bix]) == 0 or ls[bix].find(' ') >= 0:
    ls[bix] += ' '
    else:
    ls.insert(bix,'')
    diff -= 1
    bix += 2
    if bix >= 1+len(ls)/2: bix = 1

    if diff > 0:
    if len(ls[-eix]) == 0 or ls[-eix].find(' ') >= 0:
    ls[-eix] += ' '
    else:
    ls.insert(-eix,'')
    diff -= 1
    eix += 2
    if eix >= 1+len(ls)/2: eix = 1
    line = ' '.join(ls)
    return line

    --
    rzed
     
    rzed, Dec 26, 2006
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Showjumper
    Replies:
    1
    Views:
    706
    Showjumper
    Mar 19, 2005
  2. Noozer

    Block DIV within a block DIV?

    Noozer, Jan 6, 2005, in forum: HTML
    Replies:
    3
    Views:
    11,374
    Mitja
    Jan 6, 2005
  3. morrell
    Replies:
    2
    Views:
    462
    morrell
    Oct 3, 2006
  4. morrell
    Replies:
    1
    Views:
    966
    roy axenov
    Oct 10, 2006
  5. CWagon
    Replies:
    0
    Views:
    336
    CWagon
    Aug 16, 2007
Loading...

Share This Page