Re: Creating formatted output using picture strings

Discussion in 'Python' started by Peter Otten, Feb 10, 2010.

  1. Peter Otten

    Peter Otten Guest

    wrote:

    > Does Python provide a way to format a string according to a
    > 'picture' format?
    >
    > For example, if I have a string '123456789' and want it formatted
    > like '(123)-45-(678)[9]', is there a module or function that will
    > allow me to do this or do I need to code this type of
    > transformation myself?


    A basic implementation without regular expressions:

    >>> def picture(s, pic, placeholder="@"):

    .... parts = pic.split(placeholder)
    .... result = [None]*(len(parts)+len(s))
    .... result[::2] = parts
    .... result[1::2] = s
    .... return "".join(result)
    ....
    >>>
    >>> picture("123456789", "(@@@)-@@-(@@@)[@]")

    '(123)-45-(678)[9]'

    Peter
     
    Peter Otten, Feb 10, 2010
    #1
    1. Advertising

  2. 2010/2/10 Peter Otten <>:
    > wrote:
    >
    >> Does Python provide a way to format a string according to a
    >> 'picture' format?
    >>
    >> For example, if I have a string '123456789' and want it formatted
    >> like '(123)-45-(678)[9]', is there a module or function that will
    >> allow me to do this or do I need to code this type of
    >> transformation myself?

    >
    > A basic implementation without regular expressions:
    >
    >>>> def picture(s, pic, placeholder="@"):

    > ...     parts = pic.split(placeholder)
    > ...     result = [None]*(len(parts)+len(s))
    > ...     result[::2] = parts
    > ...     result[1::2] = s
    > ...     return "".join(result)
    > ...
    >>>>
    >>>> picture("123456789", "(@@@)-@@-(@@@)[@]")

    > '(123)-45-(678)[9]'
    >
    > Peter
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >


    Inspired by your answer here's another version:

    >>> def picture(s, pic):

    .... if len(s)==0: return pic
    .... if pic[0]=='#': return s[0]+picture(s[1:], pic[1:])
    .... return pic[0]+picture(s, pic[1:])
    ....
    >>> picture("123456789", "(###)-##-(###)[#]")

    '(123)-45-(678)[9]'
    >>>


    --
    http://olofb.wordpress.com
     
    Olof Bjarnason, Feb 10, 2010
    #2
    1. Advertising

  3. * Olof Bjarnason:
    > 2010/2/10 Peter Otten <>:
    >> wrote:
    >>
    >>> Does Python provide a way to format a string according to a
    >>> 'picture' format?
    >>>
    >>> For example, if I have a string '123456789' and want it formatted
    >>> like '(123)-45-(678)[9]', is there a module or function that will
    >>> allow me to do this or do I need to code this type of
    >>> transformation myself?

    >> A basic implementation without regular expressions:
    >>
    >>>>> def picture(s, pic, placeholder="@"):

    >> ... parts = pic.split(placeholder)
    >> ... result = [None]*(len(parts)+len(s))
    >> ... result[::2] = parts
    >> ... result[1::2] = s
    >> ... return "".join(result)
    >> ...
    >>>>> picture("123456789", "(@@@)-@@-(@@@)[@]")

    >> '(123)-45-(678)[9]'
    >>
    >> Peter
    >> --
    >> http://mail.python.org/mailman/listinfo/python-list
    >>

    >
    > Inspired by your answer here's another version:
    >
    >>>> def picture(s, pic):

    > ... if len(s)==0: return pic
    > ... if pic[0]=='#': return s[0]+picture(s[1:], pic[1:])
    > ... return pic[0]+picture(s, pic[1:])
    > ...
    >>>> picture("123456789", "(###)-##-(###)[#]")

    > '(123)-45-(678)[9]'


    I learned a bit by Peter Otten's example; I would have gotten to that notation
    sooner or later, but that example made it 'sooner' :).

    I think your version is cute.

    I'd probably write it in a non-recursive way, though, like

    def picture( s, pic, placeholder = "@" ):
    result = ""
    char_iter = iter( s )
    for c in pic:
    result += c if c != placeholder else next( char_iter )
    return result

    Of course this is mostly personal preference, but there is also a functional
    difference.

    With your version an IndexError will be raised if there are too /many/
    characters in s, while too few characters in s will yield "#" in the result.

    With my version a StopIteration will be raised if there are to /few/ characters
    in s, while too many characters will just have the extraneous chars ignored.


    Cheers,

    - Alf
     
    Alf P. Steinbach, Feb 10, 2010
    #3
  4. 2010/2/10 Alf P. Steinbach <>:
    > * Olof Bjarnason:
    >>
    >> 2010/2/10 Peter Otten <>:
    >>>
    >>> wrote:
    >>>
    >>>> Does Python provide a way to format a string according to a
    >>>> 'picture' format?
    >>>>
    >>>> For example, if I have a string '123456789' and want it formatted
    >>>> like '(123)-45-(678)[9]', is there a module or function that will
    >>>> allow me to do this or do I need to code this type of
    >>>> transformation myself?
    >>>
    >>> A basic implementation without regular expressions:
    >>>
    >>>>>> def picture(s, pic, placeholder="@"):
    >>>
    >>> ...     parts = pic.split(placeholder)
    >>> ...     result = [None]*(len(parts)+len(s))
    >>> ...     result[::2] = parts
    >>> ...     result[1::2] = s
    >>> ...     return "".join(result)
    >>> ...
    >>>>>>
    >>>>>> picture("123456789", "(@@@)-@@-(@@@)[@]")
    >>>
    >>> '(123)-45-(678)[9]'
    >>>
    >>> Peter
    >>> --
    >>> http://mail.python.org/mailman/listinfo/python-list
    >>>

    >>
    >> Inspired by your answer here's another version:
    >>
    >>>>> def picture(s, pic):

    >>
    >> ...   if len(s)==0: return pic
    >> ...   if pic[0]=='#': return s[0]+picture(s[1:], pic[1:])
    >> ...   return pic[0]+picture(s, pic[1:])
    >> ...
    >>>>>
    >>>>> picture("123456789", "(###)-##-(###)[#]")

    >>
    >> '(123)-45-(678)[9]'

    >
    > I learned a bit by Peter Otten's example; I would have gotten to that
    > notation sooner or later, but that example made it 'sooner' :).
    >
    > I think your version is cute.


    Thanks!

    Here's another version (maybe a little more readable?):

    def first(s): return s[0]

    def rest(s): return s[1:]

    def picture(s, pic):
    if not s: return pic
    if first(pic)=='#': return first(s)+picture(rest(s), rest(pic))
    return first(pic)+picture(s, rest(pic))


    >
    > I'd probably write it in a non-recursive way, though, like
    >
    >    def picture( s, pic, placeholder = "@" ):
    >        result = ""
    >        char_iter = iter( s )
    >        for c in pic:
    >            result += c if c != placeholder else next( char_iter )
    >        return result
    >
    > Of course this is mostly personal preference, but there is also a functional
    > difference.
    >
    > With your version an IndexError will be raised if there are too /many/
    > characters in s, while too few characters in s will yield "#" in the result.
    >
    > With my version a StopIteration will be raised if there are to /few/
    > characters in s, while too many characters will just have the extraneous
    > chars ignored.
    >
    >
    > Cheers,
    >
    > - Alf
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >




    --
    http://olofb.wordpress.com
     
    Olof Bjarnason, Feb 10, 2010
    #4
  5. Peter Otten

    MRAB Guest

    Olof Bjarnason wrote:
    > 2010/2/10 Peter Otten <>:
    >> wrote:
    >>
    >>> Does Python provide a way to format a string according to a
    >>> 'picture' format?
    >>>
    >>> For example, if I have a string '123456789' and want it formatted
    >>> like '(123)-45-(678)[9]', is there a module or function that will
    >>> allow me to do this or do I need to code this type of
    >>> transformation myself?

    >> A basic implementation without regular expressions:
    >>
    >>>>> def picture(s, pic, placeholder="@"):

    >> ... parts = pic.split(placeholder)
    >> ... result = [None]*(len(parts)+len(s))
    >> ... result[::2] = parts
    >> ... result[1::2] = s
    >> ... return "".join(result)
    >> ...
    >>>>> picture("123456789", "(@@@)-@@-(@@@)[@]")

    >> '(123)-45-(678)[9]'
    >>
    >> Peter
    >> --
    >> http://mail.python.org/mailman/listinfo/python-list
    >>

    >
    > Inspired by your answer here's another version:
    >
    >>>> def picture(s, pic):

    > ... if len(s)==0: return pic
    > ... if pic[0]=='#': return s[0]+picture(s[1:], pic[1:])
    > ... return pic[0]+picture(s, pic[1:])
    > ...
    >>>> picture("123456789", "(###)-##-(###)[#]")

    > '(123)-45-(678)[9]'
    >

    Here's a version without recursion:

    >>> def picture(s, pic):

    .... pic = pic.replace("%", "%%").replace("#", "%s")
    .... return pic % tuple(s)
    ....
    >>> picture("123456789", "(###)-##-(###)[#]")

    '(123)-45-(678)[9]'
     
    MRAB, Feb 10, 2010
    #5
  6. writes:

    > Original poster here.
    >
    > Thank you all for your ideas. I certainly learned some great techniques
    > by studying everyone's solutions!!
    >
    > I was thinking that there was a built-in function for this common(?) use
    > case which is why I shied away from writing my own in the first place
    > ... hoping to not-reinvent the wheel, etc.
    >
    > Here's the solution I came up with myself. Its not as sexy as some of
    > the posted solutions, but it does have the advantage of not failing when
    > the number of input chars <> the number of placeholders in the pic
    > string. I think it handles the edge cases pretty elegantly unless I'm
    > too close to the details to miss the obvious.
    >
    > Any feedback on what follows would be appreciated.
    >
    > # format s using a picture string
    > # stops processing when runs out of chars in s or pic string
    > # example: picture("123456789", "(@@@)-@@-(@@@)[@]")
    > def picture( s, pic, placeholder="@" ):
    > s = list( s )
    > output = []
    > for sym in pic:
    > if sym <> placeholder:
    > output.append( sym )
    > elif len( s ):
    > output.append( s.pop( 0 ) )
    > else:
    > break
    > return ''.join( output )
    >
    > # test cases
    > print picture("123456789", "(@@@)-@@-(@@@)[@]")
    > print picture("123456789ABC", "(@@@)-@@-(@@@)[@]")
    > print picture("1234", "(@@@)-@@-(@@@)[@]")
    > print picture("123456789", "(@@@)-@@-(@@@)")
    > print picture("123456789", "(@@@)-@@-(@@@)[@][@@@@@]")
    >
    > Regards,
    > Malcolm


    def picture(s, pic, placeholder='@'):
    nextchar=iter(s).next
    return ''.join(nextchar() if i == placeholder else i for i in pic)

    passes all your test cases I think (I can't be sure because you didn't
    post the expected output). The trick is that when nextchar reaches the
    end of the string 's', it raises a StopIteration which is caught by the
    generator expression.

    --
    Arnaud
     
    Arnaud Delobelle, Feb 10, 2010
    #6
  7. Peter Otten

    donn Guest

    On 10/02/2010 20:36, wrote:
    > def picture(s, pic, placeholder='@'):
    > nextchar=iter(s).next
    > return ''.join(nextchar() if i == placeholder else i for i in pic)

    Hell's teeth - even I understood that! Amazing solution.

    \d

    --
    Fonty Python and Things! -- http://otherwise.relics.co.za/wiki/Software
     
    donn, Feb 10, 2010
    #7
  8. On 2010-02-10, <> wrote:

    [regardning "picture" output format specifiers]

    > I was thinking that there was a built-in function for this
    > common(?) use case


    I haven't seen that paradigm since my one-and-only exposure to
    COBOL in a class I took back in 1979. Is the "picture" thing
    commonly used in other places than COBOL?

    --
    Grant Edwards grante Yow! Did I say I was
    at a sardine? Or a bus???
    visi.com
     
    Grant Edwards, Feb 10, 2010
    #8
  9. Peter Otten

    Guest

    On Feb 10, 2010, at 2:57 PM, Grant Edwards wrote:

    > On 2010-02-10, <> wrote:
    >
    > [regardning "picture" output format specifiers]
    >
    >> I was thinking that there was a built-in function for this
    >> common(?) use case

    >
    > I haven't seen that paradigm since my one-and-only exposure to
    > COBOL in a class I took back in 1979. Is the "picture" thing
    > commonly used in other places than COBOL?


    Seriously?

    I've seen it in dozens places other than COBOL over the years in everything from templating languages to report generators, to built-in support in a variety of languages (dBASE II anyone?).

    Haven't you ever had to get a e.g. a phone number or social security number from user input?

    S
     
    , Feb 10, 2010
    #9
  10. Peter Otten

    Tim Chase Guest

    Grant Edwards wrote:
    > [regardning "picture" output format specifiers]
    >> I was thinking that there was a built-in function for this
    >> common(?) use case

    >
    > I haven't seen that paradigm since my one-and-only exposure to
    > COBOL in a class I took back in 1979. Is the "picture" thing
    > commonly used in other places than COBOL?


    I've spotted in the wild as recently as Visual Basic 6. I don't
    know if remnants made it into Visual Fred (VB.net). I think
    they're referred to as "format strings", but they're a mystical
    (and poorly documented) suite of characters that seem to have
    accrued features like my bathtub gets mildew. Most folks just
    copy and paste the format strings from the web.

    -tkc
     
    Tim Chase, Feb 10, 2010
    #10
  11. On 2010-02-10, <> wrote:
    > On Feb 10, 2010, at 2:57 PM, Grant Edwards wrote:
    >
    >> On 2010-02-10, <> wrote:
    >>
    >> [regardning "picture" output format specifiers]
    >>
    >>> I was thinking that there was a built-in function for this
    >>> common(?) use case

    >>
    >> I haven't seen that paradigm since my one-and-only exposure to
    >> COBOL in a class I took back in 1979. Is the "picture" thing
    >> commonly used in other places than COBOL?

    >
    > Seriously?


    Seriously.

    > I've seen it in dozens places other than COBOL over the years
    > in everything from templating languages to report generators,
    > to built-in support in a variety of languages (dBASE II
    > anyone?).
    >
    > Haven't you ever had to get a e.g. a phone number or social
    > security number from user input?


    Nope. I guess it's specific to certain application areas. I've
    never done any database type stuff. I do mostly embedded,
    device drivers, networking/protocols, industrial automation,
    Unix system admin/automation, and scientific visualization.

    --
    Grant Edwards grante Yow! I once decorated my
    at apartment entirely in ten
    visi.com foot salad forks!!
     
    Grant Edwards, Feb 10, 2010
    #11
  12. Peter Otten

    Guest

    On Feb 10, 2010, at 3:40 PM, Grant Edwards wrote:

    > On 2010-02-10, <> wrote:
    >> On Feb 10, 2010, at 2:57 PM, Grant Edwards wrote:
    >>
    >>> On 2010-02-10, <> wrote:
    >>>
    >>> [regardning "picture" output format specifiers]
    >>>
    >>>> I was thinking that there was a built-in function for this
    >>>> common(?) use case
    >>>
    >>> I haven't seen that paradigm since my one-and-only exposure to
    >>> COBOL in a class I took back in 1979. Is the "picture" thing
    >>> commonly used in other places than COBOL?

    >>
    >> Seriously?

    >
    > Seriously.
    >
    >> I've seen it in dozens places other than COBOL over the years
    >> in everything from templating languages to report generators,
    >> to built-in support in a variety of languages (dBASE II
    >> anyone?).
    >>
    >> Haven't you ever had to get a e.g. a phone number or social
    >> security number from user input?

    >
    > Nope. I guess it's specific to certain application areas. I've
    > never done any database type stuff. I do mostly embedded,
    > device drivers, networking/protocols, industrial automation,
    > Unix system admin/automation, and scientific visualization.


    Yah, I've hardly ever had to get SSN input from users in a device driver ;-).

    That's what makes groups like this go 'round; we have all done different types of things which gives us all different perspectives.

    S
     
    , Feb 10, 2010
    #12
  13. Peter Otten

    John Posner Guest

    On 2/10/2010 2:57 PM, Grant Edwards wrote:
    > On 2010-02-10, <> wrote:
    >
    > [regardning "picture" output format specifiers]
    >
    >> I was thinking that there was a built-in function for this
    >> common(?) use case

    >
    > I haven't seen that paradigm since my one-and-only exposure to
    > COBOL in a class I took back in 1979. Is the "picture" thing
    > commonly used in other places than COBOL?
    >


    FWIW, Microsoft Excel supports "Custom" numeric cell formats that use a
    PICTURE-like syntax.

    -John
     
    John Posner, Feb 10, 2010
    #13
    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. Joerg Lehmann

    Print formatted Strings with Umlauts

    Joerg Lehmann, Feb 11, 2004, in forum: Python
    Replies:
    4
    Views:
    400
    Joerg Lehmann
    Feb 12, 2004
  2. Thomas Philips
    Replies:
    7
    Views:
    357
    Josiah Carlson
    May 21, 2004
  3. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    814
    Malcolm
    Jun 24, 2006
  4. Jojo
    Replies:
    9
    Views:
    416
  5. Replies:
    8
    Views:
    1,355
    Mick White
    Apr 19, 2005
Loading...

Share This Page