Pergunta

Eu sou um novato para Python e eu estou olhando para usá-lo para escrever algumas coisas EDI peludo que o nosso fornecedor exige.

Basicamente, eles precisam de um arquivo de texto de largura fixa de 80 caracteres, com determinados "pedaços" de campo com dados e outros deixados em branco. Eu tenho a documentação, então eu sei o que o comprimento de cada "pedaço" é. A resposta que eu recebo de volta é mais fácil de analisar, uma vez que já terá dados e eu posso usar "fatias" do Python para extrair o que eu preciso, mas eu não posso atribuir a uma fatia - Tentei que já porque soou como uma boa solução, e não funcionou desde cordas Python são imutáveis:)

Como eu disse eu sou realmente um novato para Python, mas eu estou animado sobre a aprendizagem que :) Como eu iria fazer isso? Idealmente, eu gostaria de ser capaz de dizer que faixa de 10-20 é igual a "Foo" e tê-lo ser a string "Foo" com 7 caracteres em branco adicionais (supondo que o referido campo tem um comprimento de 10) e tem que ser um parte do campo de 80 caracteres maior, mas não tenho certeza de como fazer o que eu estou pensando.

Foi útil?

Solução

Você não precisa atribuir a fatias, apenas construir a string usando % formatting .

Um exemplo com um formato fixo para 3 itens de dados:

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

A mesma coisa, largura do campo fornecido com os dados:

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

Separar dados e larguras de campo, e usando zip() e str.join() truques:

>>> widths=(4,10,10)
>>> items=(1,"ONE",2)
>>> "".join("%*s" % i for i in zip(widths, items))
'   1       ONE         2'
>>> 

Outras dicas

Espero que eu entendo o que você está procurando:? Alguma maneira de identificar convenientemente cada parte da linha por uma variável simples, mas de saída lo preenchido para a largura correta

O trecho a seguir podem lhe dar o que você quer

class FixWidthFieldLine(object):

    fields = (('foo', 10),
              ('bar', 30),
              ('ooga', 30),
              ('booga', 10))

    def __init__(self):
        self.foo = ''
        self.bar = ''
        self.ooga = ''
        self.booga = ''

    def __str__(self):
        return ''.join([getattr(self, field_name).ljust(width) 
                        for field_name, width in self.fields])

f = FixWidthFieldLine()
f.foo = 'hi'
f.bar = 'joe'
f.ooga = 'howya'
f.booga = 'doin?'

print f

Este rendimentos:

hi        joe                           howya                         doing     

Ele funciona armazenando uma variável de nível de classe, fields que registra a ordem em que cada campo deve aparecer na saída, juntamente com o número de colunas que o campo deve ter. Não são correspondentemente-nomeado variáveis ??de instância na __init__ que estão definidas para uma cadeia vazia inicialmente.

O método __str__ gera estes valores como uma string. Ele usa uma compreensão lista sobre o atributo fields em nível de classe, olhando para cima o valor de instância para cada campo pelo nome, e depois deixou-justificando-a de saída de acordo com as colunas. A lista resultante de campos é, então, unidos por uma cadeia vazia.

Note que este não faz entrada de análise, embora você poderia facilmente substituir o construtor para tomar uma string e analisar as colunas de acordo com as larguras de campo e de campo em fields. Ele também não verifica valores de instância que são mais longos do que a sua largura alocado.

Você pode usar justificar funções para a esquerda-justificar, direita justificar e centralizar uma string em um campo de determinada largura.

'hi'.ljust(10) -> 'hi        '

Eu sei que esta discussão é bastante antigo, mas usamos uma biblioteca chamada django-copybook . Não tem nada a ver com Django (mais). Vamos utilizá-lo para ir entre os arquivos COBOL largura fixa e python. Você cria uma classe para definir o layout do registro largura fixa e pode fácil mover entre objetos python digitado e largura fixa arquivos:

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)

Ele também pode lidar com situações semelhantes a Cobol do OCORRE funcionalidade como quando uma seção particular é repetido vezes X

É um pouco difícil de analisar sua pergunta, mas eu estou reunindo que você está recebendo um arquivo ou arquivo-como-objeto, lê-lo, e substituindo alguns dos valores com alguns resultados de lógica de negócios. É este correto?

A maneira mais simples para superar imutabilidade corda é escrever uma nova string:

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

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

Dito isto, parece que ele é importante para você que você fazer algo com esta cadeia, mas eu não sei exatamente o que é. Você está escrevendo-lo de volta para um arquivo de saída, tentando editar um arquivo no lugar, ou algo mais? Eu trago este acima porque o ato de criar uma nova string (que passa a ter o mesmo nome da variável como a cadeia de idade) deve enfatizar a necessidade de realizar uma operação de escrita explícita após a transformação.

Você pode converter a string para uma lista e fazer a manipulação fatia.

>>> text = list("some text")
>>> text[0:4] = list("fine")
>>> text
['f', 'i', 'n', 'e', ' ', 't', 'e', 'x', 't']
>>> text[0:4] = list("all")
>>> text
['a', 'l', 'l', ' ', 't', 'e', 'x', 't']
>>> import string
>>> string.join(text, "")
'all text'

É fácil função de gravação para "modificar" 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:]

Uso:

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

Eu usei o exemplo de Jarret Hardie e modificou-o ligeiramente. Isto permite a seleção do tipo de alinhamento de texto (esquerda, direita ou centralizado.)

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

Retorna:

Alex      Programmer          Salem, OR      
      Alex          Programmer      Salem, OR
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top