2012-11-22 21 views
6

Ho bisogno di estrarre dati da linee di un file di testo. I dati sono nome e le informazioni segnando formattato in questo modo:Estrarre dati da linee di un file di testo

Shyvana - 12/4/5 - Loss - 2012-11-22 
Fizz - 12/4/5 - Win - 2012-11-22 
Miss Fortune - 12/4/3 - Win - 2012-11-22 

Questo file viene generato da un'altra parte del mio piccolo programma Python in cui chiedo l'utente per il nome, ricerca il nome che entrano per assicurarsi che sia valida da un elenco di nomi, quindi chiedere uccisioni, morti, aiuti e se hanno vinto o perso. Quindi chiedo conferma e scrivo quei dati sul file su una nuova riga, e aggiungo la data alla fine in quel modo. Il codice che prepara i dati:

data = "%s - %s/%s/%s - %s - %s\n" % (
     champname, kills, deaths, assists, winloss, timestamp) 

Fondamentalmente ho voglia di leggere i dati di nuovo in un'altra parte del programma e visualizzarlo per l'utente e fare calcoli con esso, come le medie nel tempo per un particolare nome.

Sono nuovo di Python e non ho molta esperienza con la programmazione in generale, quindi la maggior parte degli esempi di suddivisione e formattazione delle stringhe che trovo sono troppo criptici per capire come adattarmi a ciò di cui ho bisogno , qualcuno potrebbe aiutare? Potrei formattare i dati scritti in modo diverso in modo che la ricerca di token sia più semplice, ma voglio che sia semplice direttamente nel file.

+0

quando lo si legge indietro, su quale struttura dati vuoi memorizzarla? – inspectorG4dget

+0

oh cielo, grazie mille a tutti, finalmente, un po 'di questa divisione del business ha senso! Darò alcuni di questi una prova e vedere cosa funziona meglio per me, grazie! e felice ringraziamento! – Kassandra

risposta

10

Quanto segue leggerà tutto in un dizionario digitato per nome giocatore. Il valore associato a ciascun player è di per sé un dizionario che funge da record con campi denominati associati agli elementi convertiti in un formato adatto per ulteriori elaborazioni.

info = {} 
with open('scoring_info.txt') as input_file: 
    for line in input_file: 
     player, stats, outcome, date = (
      item.strip() for item in line.split('-', 3)) 
     stats = dict(zip(('kills', 'deaths', 'assists'), 
          map(int, stats.split('/')))) 
     date = tuple(map(int, date.split('-'))) 
     info[player] = dict(zip(('stats', 'outcome', 'date'), 
           (stats, outcome, date))) 

print('info:') 
for player, record in info.items(): 
    print(' player %r:' % player) 
    for field, value in record.items(): 
     print(' %s: %s' % (field, value)) 

# sample usage 
player = 'Fizz' 
print('\n%s had %s kills in the game' % (player, info[player]['stats']['kills'])) 

uscita:

info: 
    player 'Shyvana': 
    date: (2012, 11, 22) 
    outcome: Loss 
    stats: {'assists': 5, 'kills': 12, 'deaths': 4} 
    player 'Miss Fortune': 
    date: (2012, 11, 22) 
    outcome: Win 
    stats: {'assists': 3, 'kills': 12, 'deaths': 4} 
    player 'Fizz': 
    date: (2012, 11, 22) 
    outcome: Win 
    stats: {'assists': 5, 'kills': 12, 'deaths': 4} 

Fizz had 12 kills in the game 

In alternativa, piuttosto che mantenere la maggior parte dei dati in dizionari, che possono rendere l'accesso nested-campo un po 'imbarazzante - info[player]['stats']['kills'] - si potrebbe invece utilizzare un po' più avanzato " generico "classe per tenerli, che ti permetterà di scrivere info2[player].stats.kills invece.

Per illustrare, qui è quasi la stessa cosa utilizzando una classe Ho chiamato Struct perché è un po 'come il tipo di dati struct del linguaggio C:

class Struct(object): 
    """ Generic container object """ 
    def __init__(self, **kwds): # keyword args define attribute names and values 
     self.__dict__.update(**kwds) 

info2 = {} 
with open('scoring_info.txt') as input_file: 
    for line in input_file: 
     player, stats, outcome, date = (
      item.strip() for item in line.split('-', 3)) 
     stats = dict(zip(('kills', 'deaths', 'assists'), 
          map(int, stats.split('/')))) 
     victory = (outcome.lower() == 'win') # change to boolean T/F 
     date = dict(zip(('year','month','day'), map(int, date.split('-')))) 
     info2[player] = Struct(champ_name=player, stats=Struct(**stats), 
           victory=victory, date=Struct(**date)) 
print('info2:') 
for rec in info2.values(): 
    print(' player %r:' % rec.champ_name) 
    print(' stats: kills=%s, deaths=%s, assists=%s' % (
      rec.stats.kills, rec.stats.deaths, rec.stats.assists)) 
    print(' victorious: %s' % rec.victory) 
    print(' date: %d-%02d-%02d' % (rec.date.year, rec.date.month, rec.date.day)) 

# sample usage 
player = 'Fizz' 
print('\n%s had %s kills in the game' % (player, info2[player].stats.kills)) 

uscita:

info2: 
    player 'Shyvana': 
    stats: kills=12, deaths=4, assists=5 
    victorious: False 
    date: 2012-11-22 
    player 'Miss Fortune': 
    stats: kills=12, deaths=4, assists=3 
    victorious: True 
    date: 2012-11-22 
    player 'Fizz': 
    stats: kills=12, deaths=4, assists=5 
    victorious: True 
    date: 2012-11-22 

Fizz had 12 kills in the game 
+0

questo sembra promettente, ho lavorato sul mio file, come posso ottenere una specifica statistica per un giocatore? il mio tutorial che sto seguendo non è molto approfondito nella sintassi del dizionario, come potrei ad esempio stampare "Fizz avuto", uccide, "nel gioco". – Kassandra

+0

@ Kassandra: Sarebbe "print" che Fizz aveva ucciso% s nel gioco '% info [' Fizz '] [' stats '] [' uccide '] '. Esistono altri modi per strutturare i dati, ad esempio utilizzando una o più classi personalizzate o magari utilizzando una classe incorporata come 'namedtuples' nel modulo' collections'. Ti lascerebbero scrivere 'info ['Fizz']. Stats.kills'. – martineau

+0

oh dio che suona bene, proverò il tuo bit qui e vedrò se riesco a ottenere ciò che voglio, non sapevo di poterlo fare in quel modo ho cercato di adattare una nuova funzione completamente configurata in il mio file per gestirlo, quando potevo semplicemente impostare alcuni vars, mal provarlo, la notazione su namedtuples è bella anche io ci proverò, grazie ancora! – Kassandra

3

Esistono due modi per leggere i dati dall'esempio del file di testo.

Primo metodo

È possibile utilizzare il modulo csv di pitone e specificare che il delimitatore è -.

Vedi http://www.doughellmann.com/PyMOTW/csv/

Secondo metodo

In alternativa, se non si desidera utilizzare questo modulo csv, si può semplicemente utilizzare il metodo split dopo aver letto ogni riga nel file come stringa.

f = open('myTextFile.txt', "r") 
lines = f.readlines() 

for line in lines: 
    words = line.split("-") # words is a list (of strings from a line), delimited by "-". 

Quindi nel tuo esempio di cui sopra, champname sarà effettivamente il primo elemento dell'elenco words, che è words[0].

+0

Non ho ancora finito di digitare prima. –

3

Si desidera utilizzare split ('-') per ottenere le parti, allora forse ancora una volta per ottenere i numeri:

for line in yourfile.readlines(): 
    data = line.split (' - ') 
    nums = [int (x) for x in data[1].split ('/')] 

dovrebbe ottenere tutto il materiale necessario nei dati [] e nums [] . In alternativa, puoi usare il modulo re e scrivere un'espressione regolare per questo. Questo non sembra abbastanza complesso per quello, però.

1

In primo luogo, si interrompe la linea in frammenti di dati

>>> name, score, result, date = "Fizz - 12/4/5 - Win - 2012-11-22".split(' - ') 
>>> name 
'Fizz' 
>>> score 
'12/4/5' 
>>> result 
'Win' 
>>> date 
'2012-11-22' 

In secondo luogo, analizzare il tuo punteggio

>>> k,d,a = map(int, score.split('/')) 
>>> k,d,a 
(12, 4, 5) 

E, infine, convertire la stringa di data in data oggetto

>>> from datetime import datetime  
>>> datetime.strptime(date, '%Y-%M-%d').date() 
datetime.date(2012, 1, 22) 

Ora avete tutte le vostre parti analizzate e normalizzate per i tipi di dati.

3
# Iterates over the lines in the file. 
for line in open('data_file.txt'): 
    # Splits the line in four elements separated by dashes. Each element is then 
    # unpacked to the correct variable name. 
    champname, score, winloss, timestamp = line.split(' - ') 

    # Since 'score' holds the string with the three values joined, 
    # we need to split them again, this time using a slash as separator. 
    # This results in a list of strings, so we apply the 'int' function 
    # to each of them to convert to integer. This list of integers is 
    # then unpacked into the kills, deaths and assists variables 
    kills, deaths, assists = map(int, score.split('/')) 

    # Now you are you free to use the variables read to whatever you want. Since 
    # kills, deaths and assists are integers, you can sum, multiply and add 
    # them easily. 
+0

Sto provando questo, ma penso che non sto usando giusto, sto cercando di fare 'info = "Miss Fortune - 12/4/3 - Win - 2012-11-22" per l'articolo in informazioni : \t champname, score, winloss, timestamp = item.split ("-") print champname ' – Kassandra

+0

Se si desidera testare con una sola riga, utilizzare 'per riga in [" Miss Fortune - 12/4/3 - Win - 2012-11-22 "]:', in una lista e non nella stringa raw. Altrimenti leggerà i singoli personaggi e tenterà di estrarre le informazioni da loro. – BoppreH

Problemi correlati