2017-05-31 8 views
3

Ich arbeite mit einer großen Anzahl von Dateien (~ 4 GB wert), die alle zwischen 1 und 100 Einträge mit dem folgenden Format enthalten (zwischen zwei *** ist ein Eintrag):Extrahieren von Informationen aus Textdatei über Regex und/oder Python

*** 
Type:status 
Origin: @z_rose yes 
Text: yes 
URL: 
ID: 95482459084427264 
Time: Mon Jul 25 08:16:06 CDT 2011 
RetCount: 0 
Favorite: false 
MentionedEntities: 20776334 
Hashtags: 
*** 
*** 
Type:status 
Origin: @aaronesilvers text 
Text: text 
URL: 
ID: 95481610861953024 
Time: Mon Jul 25 08:12:44 CDT 2011 
RetCount: 0 
Favorite: false 
MentionedEntities: 2226621 
Hashtags: 
*** 
*** 
Type:status 
Origin: @z_rose text 
Text: text and stuff 
URL: 
ID: 95480980026040320 
Time: Mon Jul 25 08:10:14 CDT 2011 
RetCount: 0 
Favorite: false 
MentionedEntities: 20776334 
Hashtags: 
*** 

Jetzt möchte ich irgendwie diese in Pandas für die Massenanalyse importieren, aber natürlich würde ich diese Pandas umgehen kann in ein Format konvertieren. Deshalb möchte ich ein Skript schreiben, das die oben in eine CSV konvertiert etwas wie folgt aussehen (Benutzer ist die Dateititel):

User Type Origin    Text URL ID    Time       RetCount Favorite MentionedEntities Hashtags 
4012987 status @z_rose yes   yes Null 95482459084427264 Mon Jul 25 08:16:06 CDT 2011 0   false 20776334   Null 
4012987 status @aaronsilvers text text Null 95481610861953024 Mon Jul 25 08:12:44 CDT 2011 0   false 2226621   Null 

(Formatierung ist nicht perfekt, aber hoffentlich bekommen Sie die Idee)

Ich hatte einige Code arbeiten, die auf der Grundlage der es regelmäßig Informationen in Segmenten von 12 funktionierte, aber leider einige der Dateien enthalten einige Whitelines in einigen Bereichen. Was ich im Grunde zu tun suchen, ist:

fields[] =['User', 'Type', 'Origin', 'Text', 'URL', 'ID', 'Time', 'RetCount', 'Favorite', 'MentionedEntities', 'Hashtags'] 
starPair = 0; 
User = filename; 
read(file) 
#Determine if the current entry has ended 
if(stringRead=="***"){ 
    if(starPair == 0) 
     starPair++; 
    if(starPair == 1){ 
     row=row++; 
     starPair = 0; 
    } 
} 
#if string read matches column field 
if(stringRead == fields[]) 
    while(strRead != fields[]) #until next field has been found 
     #extract all characters into correct column field 

jedoch strittig, dass einige Felder, die Worte in den Feldern [] .. enthalten kann ich für eine \ n char zunächst prüfen kann, was stark die Menge reduzieren würde von fehlerhaften Einträgen, aber würde sie nicht beseitigen.

Kann mir jemand in die richtige Richtung zeigen?

Vielen Dank im Voraus!

+0

Woher kommt der Benutzer? – depperm

+0

Oh mein Schlechter, Benutzer wird vom textfile Name extrahiert (alle Textdateien sind durch userID). – user3394131

+0

Vielleicht einfach versuchen, durch "***" zu teilen und dann das Ergebnis durch Newline zu teilen? Dann verbinden Sie diese mit einer Zeichenfolge und drucken sie in eine Textdatei. – Eswemenasja

Antwort

1

Ihr Code/Pseudo-Code sieht nicht wie Python aus, sondern weil Sie das Python-Tag hier haben, ist, wie ich es tun würde. Lesen Sie zuerst die Datei in eine Zeichenfolge, gehen Sie dann durch jedes Feld und erstellen Sie einen regulären Ausdruck, um den Wert danach zu finden, drücken Sie das Ergebnis in eine 2-D-Liste und geben Sie dann diese 2-D-Liste in eine CSV-Datei aus. Außerdem sieht Ihre CSV eher wie ein TSV aus (Tabulator getrennt statt durch Komma getrennt).

import re 
import csv 

filename='4012987' 
User=filename 

# read your file into a string 
with open(filename, 'r') as myfile: 
    data=myfile.read() 

fields =['Type', 'Origin', 'Text', 'URL', 'ID', 'Time', 'RetCount', 'Favorite', 'MentionedEntities', 'Hashtags'] 
csvTemplate = [['User','Type', 'Origin', 'Text', 'URL', 'ID', 'Time', 'RetCount', 'Favorite', 'MentionedEntities', 'Hashtags']] 

# for each field use regex to get the entry 
for n,field in enumerate(fields): 
    matches = re.findall(field+':\s?([^\n]*)\n+', data) 
    # this should run only the first time to fill your 2d list with the right amount of lists 
    while len(csvTemplate)<=len(matches): 
    csvTemplate.append([None]*(len(fields)+1)) # Null isn't a python reserved word 
    for e,m in enumerate(matches): 
    if m != '': 
     csvTemplate[e+1][n+1]=m.strip() 
# set the User column 
for i in range(1,len(csvTemplate)): 
    csvTemplate[i][0] = User 
# output to csv....if you want tsv look at https://stackoverflow.com/a/29896136/3462319 
with open("output.csv", "wb") as f: 
    writer = csv.writer(f) 
    writer.writerows(csvTemplate) 
+0

Mein Laptop Akku funktioniert nicht richtig, Ill hoffentlich in der Lage, dies am Wochenende zu testen! Danke für die Antwort auf jeden Fall! – user3394131

+0

Hallo, mein Laptop ist jetzt repariert, Entschuldigung für die Verzögerung bei der Beantwortung. Ich musste "wb" in "w" ändern, weil es sonst nicht laufen würde. Vielen Dank! – user3394131

+0

wollte nur nachverfolgen, dass es scheint perfekt zu funktionieren. Am Ende hatte ich tatsächlich fast 20 GB Daten und alle Samples, die ich getestet habe, waren perfekt. Danke vielmals! – user3394131

2

Sie können eine Kombination aus einem regulären Ausdrücken und einem dict Verständnis:

import regex as re, pandas as pd 

rx_parts = re.compile(r'^{}$(?s:.*?)^{}$'.format(re.escape('***'), re.escape('***')), re.MULTILINE) 
rx_entry = re.compile(r'^(?P<key>\w+):[ ]*(?P<value>.+)$', re.MULTILINE) 

result = ({m.group('key'): m.group('value') 
      for m in rx_entry.finditer(part.group(0))} 
      for part in rx_parts.finditer(your_string_here)) 

df = pd.DataFrame(result) 
print(df) 

Welche

Favorite Hashtags     ID MentionedEntities    Origin \ 
0 false   95482459084427264   20776334   @z_rose yes 
1 false   95481610861953024   2226621 @aaronesilvers text 
2 false   95480980026040320   20776334   @z_rose text 

    RetCount   Text       Time Type URL 
0  0    yes Mon Jul 25 08:16:06 CDT 2011 status  
1  0   text Mon Jul 25 08:12:44 CDT 2011 status  
2  0 text and stuff Mon Jul 25 08:10:14 CDT 2011 status  


Erklärung ergibt:

  1. Dividieren der Strang in verschiedene Teile, die von *** beidseitig umgeben
  2. Suchen nach Schlüsselwerte Paare in jeder Zeile
  3. Setzen alle Paare in einem dict

Wir einen Generator von Wörterbüchern am Ende mit die wir dann in pandas einspeisen.

Hinweise:

Der Code mit großen Datenmengen, nicht besonders nicht 4gb getestet. Darüber hinaus benötigen Sie das neuere Modul regex, damit der Ausdruck funktioniert.

+0

Mein Laptop-Akku funktioniert nicht richtig, Ill hoffentlich in der Lage, dies am Wochenende zu testen! Danke für die Antwort auf jeden Fall! – user3394131

+0

Hatte eine neue Batterie bestellt, mein Laptop funktioniert endlich wieder, Entschuldigung für die Verzögerung bei der Beantwortung. Ich erhalte die folgende Fehlermeldung aber: 'A: \ programmas \ Anaconda \ lib \ sre_parse.py in _parse (Quelle, Staat) 760 Break 761, wenn das Zeichen nicht in FLAGS: -> 762 Raise Quelle. Fehler ("unknown Flag", len (char)) 763 verbose = state.flags & SRE_FLAG_VERBOSE 764 weiter ' und ich kann nicht scheinen, um herauszufinden, wie es zu beheben. – user3394131

Verwandte Themen