2012-10-11 7 views
8

Sto tentando di analizzare un file di prova. il file ha nome utente, indirizzo e telefono nel seguente formato:Dati file di testo che analizzano le righe e vengono emesse come colonne

Name: John Doe1 
address : somewhere 
phone: 123-123-1234 

Name: John Doe2 
address : somewhere 
phone: 123-123-1233 

Name: John Doe3 
address : somewhere 
phone: 123-123-1232 

Solo per quasi 10k utenti:) quello che vorrei fare è di convertire quelle file di colonne, ad esempio:

Name: John Doe1    address : somewhere   phone: 123-123-1234 
Name: John Doe2    address : somewhere   phone: 123-123-1233 
Name: John Doe3    address : somewhere   phone: 123-123-1232 

Preferirei farlo in bash ma se sai come farlo in python sarebbe bello anche, il file che ha questa informazione è in/root/docs/information. Qualsiasi consiglio o aiuto sarebbe molto apprezzato.

+2

Cosa hai provato? – nneonneo

+0

Buona domanda iniziale, @tafiela. Ma non dimenticare di indicare nelle domande successive cosa hai provato a fare. – Yamaneko

+0

L'indirizzo è in realtà solo una riga dopo i due punti? –

risposta

5

Un modo con GNU awk:

awk 'BEGIN { FS="\n"; RS=""; OFS="\t\t" } { print $1, $2, $3 }' file.txt 

risultati:

Name: John Doe1  address : somewhere  phone: 123-123-1234 
Name: John Doe2  address : somewhere  phone: 123-123-1233 
Name: John Doe3  address : somewhere  phone: 123-123-1232 

Si noti che, ho impostato il separatore di file di output (OFS) su due caratteri di tabulazione (\t\t). Puoi cambiarlo con qualsiasi personaggio o set di caratteri che ti piace. HTH.

+0

+1 - mi hai battuto al punch. –

+0

Cosa 'RS' fa? – Yamaneko

+1

@VictorHugo: 'RS' è l'abbreviazione di separatore di record. Di default 'RS' è impostato su' \ n' o newline. Ciò consente a 'awk' di elaborare il file riga per riga. Quando lo impostiamo su nothing (o "" "), stiamo effettivamente cambiando la definizione di una riga di" awk ". Poiché ciascuno dei record è separato da linee vuote, l'impostazione di 'RS =" "' rappresenta una soluzione semplice. HTH. – Steve

0

In Python:

results = [] 
cur_item = None 

with open('/root/docs/information') as f: 
    for line in f.readlines(): 
     key, value = line.split(':', 1) 
     key = key.strip() 
     value = value.strip() 

     if key == "Name": 
      cur_item = {} 
      results.append(cur_item) 
     cur_item[key] = value 

for item in results: 
    # print item 
+0

Dovresti precisare la lingua;) –

+0

@sputnick Non sono proprio così ho capito cosa intendi –

+0

Basta dire la lingua: è Python. – Matthias

0

Si dovrebbe essere in grado di analizzare questo utilizzando il metodo split() su una stringa:

line = "Name: John Doe1" 
key, value = line.split(":") 
print(key) # Name 
print(value) # John Doe1 
3

Con una breve Perl one-liner:

$ perl -ne 'END{print "\n"}chomp; /^$/ ? print "\n" : print "$_\t\t"' file.txt 

USCITA

Name: John Doe1   address : somewhere    phone: 123-123-1234 
Name: John Doe2   address : somewhere    phone: 123-123-1233 
Name: John Doe3   address : somewhere    phone: 123-123-1232 
1

Questo sembra fare praticamente ciò che si vuole:

information = 'information' # file path 

with open(information, 'rt') as input: 
    data = input.read() 

data = data.split('\n\n') 

for group in data: 
    print group.replace('\n', '  ') 

uscita:

0.123.516,41 mila
Name: John Doe1  address : somewhere  phone: 123-123-1234 
Name: John Doe2  address : somewhere  phone: 123-123-1233 
Name: John Doe3  address : somewhere  phone: 123-123-1232  
0

È possibile scorrere su di linee e stamparle in colonne come questo -

for line in open("/path/to/data"): 
    if len(line) != 1: 
     # remove \n from line's end and make print statement 
     # skip the \n it adds in the end to continue in our column 
     print "%s\t\t" % line.strip(), 
    else: 
     # re-use the blank lines to end our column 
     print 
2

con pasta, siamo in grado di unire le righe nel file:

$ paste -s -d"\t\t\t\n" file 
Name: John Doe1 address : somewhere  phone: 123-123-1234 
Name: John Doe2 address : somewhere  phone: 123-123-1233 
Name: John Doe3 address : somewhere  phone: 123-123-1232 
+0

No così ben formulato =) –

+0

@sputnick Vero, ma questa è la parte difficile. Ci sono una miriade di utility per espandere le schede. –

+0

Sì, ma in questo caso sono necessari 2 tubi;) –

1

Lo so che non ha citato awk, ma risolve il problema bene:

awk 'BEGIN {RS="";FS="\n"} {print $1,$2,$3}' data.txt 
0
#!/usr/bin/env python 

def parse(inputfile, outputfile): 
    dictInfo = {'Name':None, 'address':None, 'phone':None} 
    for line in inputfile: 
    if line.startswith('Name'): 
     dictInfo['Name'] = line.split(':')[1].strip() 
    elif line.startswith('address'): 
     dictInfo['address'] = line.split(':')[1].strip() 
    elif line.startswith('phone'): 
     dictInfo['phone'] = line.split(':')[1].strip() 
     s = 'Name: '+dictInfo['Name']+'\t'+'address: '+dictInfo['address'] \ 
      +'\t'+'phone: '+dictInfo['phone']+'\n' 
     outputfile.write(s) 

if __name__ == '__main__': 
    with open('output.txt', 'w') as outputfile: 
    with open('infomation.txt') as inputfile: 
     parse(inputfile, outputfile) 
0

Una soluzione che utilizza sed.

cat input.txt | sed '/^$/d' | sed 'N; s:\n:\t\t:; N; s:\n:\t\t:' 
  1. primo tubo, sed '/^$/d', rimuove le righe vuote.
  2. Secondo tubo, sed 'N; s:\n:\t\t:; N; s:\n:\t\t:', combina le linee.
 
Name: John Doe1  address : somewhere  phone: 123-123-1234 
Name: John Doe2  address : somewhere  phone: 123-123-1233 
Name: John Doe3  address : somewhere  phone: 123-123-1232 
1

maggior parte delle soluzioni qui sono solo riformattare i dati nel file che si sta leggendo. Forse è tutto ciò che vuoi.

Se si desidera effettivamente analizzare i dati, inserirli in una struttura dati.

Questo esempio in Python:

data="""\ 
Name: John Doe2 
address : 123 Main St, Los Angeles, CA 95002 
phone: 213-123-1234 

Name: John Doe1 
address : 145 Pearl St, La Jolla, CA 92013 
phone: 858-123-1233 

Name: Billy Bob Doe3 
address : 454 Heartland St, Mobile, AL 00103 
phone: 205-123-1232""".split('\n\n')  # just a fill-in for your file 
              # you would use `with open(file) as data:` 

addr={} 
w0,w1,w2=0,0,0    # these keep track of the max width of the field 
for line in data: 
    fields=[e.split(':')[1].strip() for e in [f for f in line.split('\n')]] 
    nam=fields[0].split() 
    name=nam[-1]+', '+' '.join(nam[0:-1]) 
    addr[(name,fields[2])]=fields 
    w0,w1,w2=[max(t) for t in zip(map(len,fields),(w0,w1,w2))] 

Ora si ha la libertà di ordinare, modificare il formato, messo in banca dati, ecc

Questo stampa il formato con cui i dati, in ordine:

for add in sorted(addr.keys()): 
    print 'Name: {0:{w0}} Address: {1:{w1}} phone: {2:{w2}}'.format(*addr[add],w0=w0,w1=w1,w2=w2) 

Stampe:

Name: John Doe1  Address: 145 Pearl St, La Jolla, CA 92013 phone: 858-123-1233 
Name: John Doe2  Address: 123 Main St, Los Angeles, CA 95002 phone: 213-123-1234 
Name: Billy Bob Doe3 Address: 454 Heartland St, Mobile, AL 00103 phone: 205-123-1232 

Questo è ordinato in base al cognome, nome utilizzato nella chiave dict.

Ora Stampa esso allineati secondo prefisso:

for add in sorted(addr.keys(),key=lambda x: addr[x][2]): 
    print 'Name: {0:{w0}} Address: {1:{w1}} phone: {2:{w2}}'.format(*addr[add],w0=w0,w1=w1,w2=w2) 

Stampe:

Name: Billy Bob Doe3 Address: 454 Heartland St, Mobile, AL 00103 phone: 205-123-1232 
Name: John Doe2  Address: 123 Main St, Los Angeles, CA 95002 phone: 213-123-1234 
Name: John Doe1  Address: 145 Pearl St, La Jolla, CA 92013 phone: 858-123-1233 

Ma, dal momento che si hanno i dati in un dizionario indicizzata, è possibile stamparlo come un tavolo invece ordinati per CAP:

# print table header 
print '|{0:^{w0}}|{1:^{w1}}|{2:^{w2}}|'.format('Name','Address','Phone',w0=w0+2,w1=w1+2,w2=w2+2) 
print '|{0:^{w0}}|{1:^{w1}}|{2:^{w2}}|'.format('----','-------','-----',w0=w0+2,w1=w1+2,w2=w2+2) 
# print data sorted by last field of the address - probably a zip code 
for add in sorted(addr.keys(),key=lambda x: addr[x][1].split()[-1]): 
    print '|{0:>{w0}}|{1:>{w1}}|{2:>{w2}}|'.format(*addr[add],w0=w0+2,w1=w1+2,w2=w2+2) 

Stampe:

|  Name  |    Address    | Phone  | 
|  ----  |    -------    | -----  | 
| Billy Bob Doe3| 454 Heartland St, Mobile, AL 00103| 205-123-1232| 
|  John Doe1| 145 Pearl St, La Jolla, CA 92013| 858-123-1233| 
|  John Doe2| 123 Main St, Los Angeles, CA 95002| 213-123-1234| 
Problemi correlati