2009-06-08 21 views
4

HALLO allePython: Lese Teil einer Textdatei

Ich bin neu in Python und Programmierung. Ich brauche in Stücke einer großen Textdatei zu lesen, sieht Format wie folgt aus:

<word id="8" form="hibernis" lemma="hibernus1" postag="n-p---nb-" head-"7" relation="ADV"/> 

Ich brauche die form, lemma und postag Informationen. z.B. für oben brauche ich hibernis, hibernus1 und n-p---nb-.

Wie sage ich Python zu lesen, bis es Formular erreicht, weiterzulesen, bis es das Anführungszeichen " erreicht und lesen Sie dann die Informationen zwischen den Anführungszeichen "hibernis"? Wirklich damit zu kämpfen.

Meine bisherigen Versuche waren, die Interpunktion zu entfernen, den Satz zu spalten und dann die Informationen, die ich brauche, aus einer Liste zu ziehen. Wenn ich Probleme habe, Python über die ganze Datei zu iterieren, kann ich das nur für eine Zeile erreichen. Mein Code ist unten:

f=open('blank.txt','r') 
quotes=f.read() 
noquotes=quotes.replace('"','') 
f.close() 

rf=open('blank.txt','w') 
rf.write(noquotes) 
rf.close() 

f=open('blank.txt','r') 
finished = False 
postag=[] 
while not finished: 
    line=f.readline() 
    words=line.split() 
    postag.append(words[4]) 
    postag.append(words[6]) 
    postag.append(words[8])    
    finished=True 

schätzen würde jedes Feedback/Kritik

dank

Antwort

2

Ich würde vorschlagen, den regulären Ausdruck Modul: re

Etwas in diesen vielleicht Linien?

#!/usr/bin/python 
import re 

if __name__ == '__main__': 
    data = open('x').read() 
    RE = re.compile('.*form="(.*)" lemma="(.*)" postag="(.*?)"', re.M) 
    matches = RE.findall(data) 
    for m in matches: 
     print m 

Dies davon ausgehen, dass die <word ...> Linien sind jeweils auf einer einzigen Zeile und dass jeder Teil in exakt dieser Reihenfolge ist, und dass Sie nicht brauchen, mit voller XML-Analyse zu beschäftigen.

+0

Danke Retracile. Probieren Sie einfach Ihren Code und es ist genau das, was ich brauche. Schätze wirklich deine Hilfe. Ich habe das re-Modul zuerst versucht und hatte den folgenden Ausdruck: für Zeile in f: wenn re.match ("(. *) (F | 1) orm (. *)", Zeile): print >> rfformat, line, –

+0

, aber dummerweise gab er diese Methode auf und entschied sich für die Listenmethode. Ich werde jetzt das Modul re studieren und stellen Sie sicher, ich weiß, was Ihr Code tut –

+0

Vielen Dank wieder, sehr geschätzt –

1

Ist Ihre Datei korrekt XML? Wenn ja, versuchen Sie einen SAX-Parser:

import xml.sax 
class Handler (xml.sax.ContentHandler): 
    def startElement (self, tag, attrs): 
     if tag == 'word': 
      print 'form=', attrs['form'] 
      print 'lemma=',attrs['lemma'] 
      print 'postag=',attrs['postag'] 

ch = Handler() 
f = open ('myfile') 
xml.sax.parse (f, ch) 

(das ist grob .. es kann nicht ganz richtig sein).

+0

hi da, datei ist alles xml, muss sax parser schauen und auch schöne suppe unten erwähnt. Wird wahrscheinlich die Dinge viel einfacher machen.Danke für Ihre Hilfe –

+0

Denken Sie daran, dass BeautifulSoup nicht Teil der Standard-Python-Distribution ist (für den Fall, dass Sie dieses Skript in Umgebungen verwenden müssen, in denen Sie keine Berechtigung zum Hinzufügen von Paketen haben). – eduffy

1

Neben der üblichen RegEx Antwort, da dies eine Form von XML zu sein scheint, Sie so etwas wie BeautifulSoup versuchen könnte (http://www.crummy.com/software/BeautifulSoup/)

Es ist sehr einfach zu bedienen, und Tags finden/Attribute in Dinge wie HTML/XML, auch wenn sie nicht "gut geformt" sind. Könnte einen Blick wert sein.

0

Parsing xml von Hand ist in der Regel die falsche Sache. Zum einen bricht Ihr Code ab, wenn in einem der Attribute ein Zitat existiert. Abrufen der Attribute von einem xml Parser ist wahrscheinlich sauberer und weniger fehleranfällig.

Ein solcher Ansatz kann auch zu Problemen beim Parsen der gesamten Datei führen, wenn Sie Zeilen haben, die nicht mit dem Format übereinstimmen.Sie können entweder damit umgehen, indem eine parseline Methode (so etwas wie

def parse (line): 
     try: 
      return parsed values here 
     except: 

erstellen, können Sie auch diese Vereinfachung mit Filter und Kartenfunktionen:

lines = filter(lambda line: parseable(line), f.readlines()) 
values = map (parse, lines) 
0

einfach Ihr Problem zu markieren:

finished = False 
counter = 0 
while not finished: 
    counter += 1 
    finished=True 
print counter 
+0

in der Tat ist Ihre Antwort die beste. :) Alle anderen waren nicht daran interessiert, den Code zu korrigieren. – jacob

0

Mit regulären Ausdrücken, dies ist der Kern (Sie können den file.readline() Teil tun):

import re 
line = '<word id="8" form="hibernis" lemma="hibernus1" postag="n-p---nb-" head-"7" relation="ADV"/>' 
r = re.compile('form="([^"]*)".*lemma="([^"]*)".*postag="([^"]*)"') 
match = r.search(line) 
print match.groups() 

>>> 
('hibernis', 'hibernus1', 'n-p---nb-') 
>>> 
0

Erstens, verbringen Sie nicht viel Zeit, um Ihre Datei neu zu schreiben. Es ist im Allgemeinen eine Zeitverschwendung. Die Verarbeitung, um die Tags zu bereinigen und zu parsen, ist so schnell, dass Sie vollkommen zufrieden sind, immer von der Quelldatei zu arbeiten.

source= open("blank.txt", "r") 
for line in source: 
    # line has a tag-line structure 
    # <word id="8" form="hibernis" lemma="hibernus1" postag="n-p---nb-" head-"7" relation="ADV"/> 
    # Assumption -- no spaces in the quoted strings. 
    parts = line.split() 
    # parts is [ '<word', 'id="8"', 'form="hibernis"', ... ] 
    assert parts[0] == "<word" 
    nameValueList = [ part.partition('=') for part in parts[1:] ] 
    # nameValueList is [ ('id','=','"8"'), ('form','=','"hibernis"'), ... ] 
    attrs = dict((n,eval(v)) for n, _, v in nameValueList) 
    # attrs is { 'id':'8', 'form':'hibernis', ... } 
    print attrs['form'], attrs['lemma'], attrs['posttag'] 
+0

Gibt es wirklich einen Bedarf für Eval hier? würde nicht strippen ('' ') eine bessere Option sein? – SilentGhost

+0

@SilentGhost: das ist einer von diesen sechs von einem, ein halbes Dutzend der anderen Situationen. Manche Leute sagen gerne "eval ist böse" - was weitgehend ist Es ist aber auch ein Zufall, dass die im Beispiel gezeigte Zeichenkette eine gültige Python-Zeichenkette zu sein scheint.Vielleicht gibt es Escape-Zeichen, die sich von Python unterscheiden, was eval wegen der Nicht-Python-Zeichenkettensyntax ungültig macht: –

0

wow, ihr seid schnell :) Wenn Sie alle Attribute einer Liste auswählen (und die Reihenfolge bekannt ist), dann kann man so etwas wie folgt verwenden:

import re 
print re.findall('"(.+?)"',INPUT) 

INPUT ist ein Zeile wie:

<word id="8" form="hibernis" lemma="hibernus1" postag="n-p---nb-" head="7" relation="ADV"/> 

und die gedruckte Liste ist:

['8', 'hibernis', 'hibernus1', 'n-p---nb-', '7', 'ADV'] 
5

Wenn es XML ist, verwenden ElementTree es zu analysieren:

from xml.etree import ElementTree 

line = '<word id="8" form="hibernis" lemma="hibernus1" postag="n-p---nb-" head="7" relation="ADV"/>' 

element = ElementTree.fromstring(line) 

Für jedes XML-Element, das Sie leicht den Namen extrahieren und alle Attribute:

>>> element.tag 
'word' 
>>> element.attrib 
{'head': '7', 'form': 'hibernis', 'postag': 'n-p---nb-', 'lemma': 'hibernus1', 'relation': 'ADV', 'id': '8'} 

Also, wenn Sie ein Dokument mit einem haben Bündel von word XML-Elemente, so etwas wie dies die Informationen, die Sie von jedem wollen extrahieren:

from xml.etree import ElementTree 

XML = ''' 
<words> 
    <word id="8" form="hibernis" lemma="hibernus1" postag="n-p---nb-" head="7" relation="ADV"/> 
</words>''' 

root = ElementTree.fromstring(XML) 

for element in root.findall('word'): 
    form = element.attrib['form'] 
    lemma = element.attrib['lemma'] 
    postag = element.attrib['postag'] 

    print form, lemma, postag 

uns e parse() anstelle von fromstring() wenn Sie nur einen Dateinamen haben.

+0

das ist eine nette Lösung:) – jacob

+0

das ist wirklich hilfreich, danke :) –

Verwandte Themen