Writing/parsing a fixed width file using Python

前端 未结 8 1713
清歌不尽
清歌不尽 2020-12-14 11:01

I\'m a newbie to Python and I\'m looking at using it to write some hairy EDI stuff that our supplier requires.

Basically they need an 80-character fixed width text f

相关标签:
8条回答
  • 2020-12-14 11:30

    You don't need to assign to slices, just build the string using % formatting.

    An example with a fixed format for 3 data items:

    >>> fmt="%4s%10s%10s"
    >>> fmt % (1,"ONE",2)
    '   1       ONE         2'
    >>> 
    

    Same thing, field width supplied with the data:

    >>> fmt2 = "%*s%*s%*s"
    >>> fmt2 % (4,1, 10,"ONE", 10,2)
    '   1       ONE         2'
    >>> 
    

    Separating data and field widths, and using zip() and str.join() tricks:

    >>> widths=(4,10,10)
    >>> items=(1,"ONE",2)
    >>> "".join("%*s" % i for i in zip(widths, items))
    '   1       ONE         2'
    >>> 
    
    0 讨论(0)
  • 2020-12-14 11:31

    It's a little difficult to parse your question, but I'm gathering that you are receiving a file or file-like-object, reading it, and replacing some of the values with some business logic results. Is this correct?

    The simplest way to overcome string immutability is to write a new string:

    # Won't work:
    test_string[3:6] = "foo"
    
    # Will work:
    test_string = test_string[:3] + "foo" + test_string[6:]
    

    Having said that, it sounds like it's important to you that you do something with this string, but I'm not sure exactly what that is. Are you writing it back to an output file, trying to edit a file in place, or something else? I bring this up because the act of creating a new string (which happens to have the same variable name as the old string) should emphasize the necessity of performing an explicit write operation after the transformation.

    0 讨论(0)
  • 2020-12-14 11:32

    You can use justify functions to left-justify, right-justify and center a string in a field of given width.

    'hi'.ljust(10) -> 'hi        '
    
    0 讨论(0)
  • 2020-12-14 11:37

    It is easy to write function to "modify" string.

    def change(string, start, end, what):
        length = end - start
        if len(what)<length: what = what + " "*(length-len(what))
        return string[0:start]+what[0:length]+string[end:]
    

    Usage:

    test_string = 'This is test string'
    
    print test_string[5:7]  
    # is
    test_string = change(test_string, 5, 7, 'IS')
    # This IS test string
    test_string = change(test_string, 8, 12, 'X')
    # This IS X    string
    test_string = change(test_string, 8, 12, 'XXXXXXXXXXXX')
    # This IS XXXX string
    
    0 讨论(0)
  • 2020-12-14 11:38

    I know this thread is quite old, but we use a library called django-copybook. It has nothing to do with django (anymore). We use it to go between fixed width cobol files and python. You create a class to define your fixed width record layout and can easy move between typed python objects and fixed width files:

    USAGE:
    class Person(Record):
        first_name = fields.StringField(length=20)
        last_name = fields.StringField(length=30)
        siblings = fields.IntegerField(length=2)
        birth_date = fields.DateField(length=10, format="%Y-%m-%d")
    
    >>> fixedwidth_record = 'Joe                 Smith                         031982-09-11'
    >>> person = Person.from_record(fixedwidth_record)
    >>> person.first_name
    'Joe'
    >>> person.last_name
    'Smith'
    >>> person.siblings
    3
    >>> person.birth_date
    datetime.date(1982, 9, 11)
    

    It can also handle situations similar to Cobol's OCCURS functionality like when a particular section is repeated X times

    0 讨论(0)
  • 2020-12-14 11:49

    I used Jarret Hardie's example and modified it slightly. This allows for selection of type of text alignment(left, right or centered.)

    class FixedWidthFieldLine(object):
        def __init__(self, fields, justify = 'L'):
            """ Returns line from list containing tuples of field values and lengths. Accepts
                justification parameter.
                FixedWidthFieldLine(fields[, justify])
    
                fields = [(value, fieldLenght)[, ...]]
            """
            self.fields = fields
    
            if (justify in ('L','C','R')):
                self.justify = justify
            else:
                self.justify = 'L'
    
        def __str__(self):
            if(self.justify == 'L'):
                return ''.join([field[0].ljust(field[1]) for field in self.fields])
            elif(self.justify == 'R'):
                return ''.join([field[0].rjust(field[1]) for field in self.fields])
            elif(self.justify == 'C'):
                return ''.join([field[0].center(field[1]) for field in self.fields])
    
    fieldTest = [('Alex', 10),
             ('Programmer', 20),
             ('Salem, OR', 15)]
    
    f = FixedWidthFieldLine(fieldTest)
    print f
    f = FixedWidthFieldLine(fieldTest,'R')
    print f
    

    Returns:

    Alex      Programmer          Salem, OR      
          Alex          Programmer      Salem, OR
    
    0 讨论(0)
提交回复
热议问题