list, fehlende felder einfügen und sortieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
nihilist
User
Beiträge: 28
Registriert: Dienstag 13. Februar 2007, 07:02

Hi,
Ich habe folgende Beispieldatei:

Code: Alles auswählen

Text1: 1.10-1; Text2: misc; Text3: 2-1.0; Text4: BlaBlaBla;
Text1: 1.02-1; Text3: 2-1.0; Text4: BlaBlaBla;
Text1: 1.00-1; Text2: misc; Text4: BlaBlaBla;
Text1: 1.00-1; Text4: BlaBlaBla;
Text1: blabla;
Text1: 1.00-1; Text3: 2-1.0; Text4: BlaBlaBla;
[...]
Ich möchte erreichen das in jeder Zeile alle "Text*:" Felder vorkommen und diese sortiert sind. (Reihenfolge ist egal, nur sollte es in jeder Zeile gleich sein.)
Sollte ein Feld in einer Zeile nicht vorkommen soll dieses eingefügt werden.

Ich habe versucht das file in eine liste einzulesen und mit re.search und einigen If-abfragen zum Ergebnis zu kommen, leider fehlt mir wohl mal wieder der entscheidende Tip.

Code: Alles auswählen

#!/usr/bin/python
import re
f = file('test.txt', 'r')
for line in f:
    reg1 = re.search(r'Text1: ([\w].*)',line)
    reg2 = re.search(r'Text2: ([\w].*)',line)
    reg3 = re.search(r'Text3: ([\w].*)',line)
    reg4 = re.search(r'Text4: ([\w].*)',line)
    sline = line.split(";")
    if reg1:
        sline.insert(0,reg1.group(1))
    else:
        sline.insert(0,"Text1: ")
     if reg2:
        sline.insert(1,reg2.group(1))
    else:
        sline.insert(1,"Text2: ")
    if reg3:
        sline.insert(2,reg3.group(1))
    else:
        sline.insert(2,"Text3: ")
    if reg4:
        sline.insert(3,reg4.group(1))
    else:
        sline.insert(3,"Text4: ")
    print sline
f.close()

Ausgabe:
(Ich habe group(1) durch group() ersetzt um die Ausgabe etwas besser lesbar zu machen.)

Code: Alles auswählen

['Text1: 1.10-1; Text2: misc; Text3: 2-1.0; Text4: BlaBlaBla;', 'Text2: misc; Text3: 2-1.0; Text4: BlaBlaBla;', 'Text3: 2-1.0; Text4: BlaBlaBla;', 'Text4: BlaBlaBla;', 'Text1: 1.10-1', ' Text2: misc', ' Text3: 2-1.0', ' Text4: BlaBlaBla', '\n']
['Text1: 1.02-1; Text3: 2-1.0; Text4: BlaBlaBla;', 'Text2: ', 'Text3: 2-1.0; Text4: BlaBlaBla;', 'Text4: BlaBlaBla;', 'Text1: 1.02-1', ' Text3: 2-1.0', ' Text4: BlaBlaBla', '\n']
['Text1: 1.00-1; Text2: misc; Text4: BlaBlaBla;', 'Text2: misc; Text4: BlaBlaBla;', 'Text3: ', 'Text4: BlaBlaBla;', 'Text1: 1.00-1', ' Text2: misc', ' Text4: BlaBlaBla', '\n']
['Text1: 1.00-1; Text4: BlaBlaBla;', 'Text2: ', 'Text3: ', 'Text4: BlaBlaBla;', 'Text1: 1.00-1', ' Text4: BlaBlaBla', '\n']
['Text1: blabla;', 'Text2: ', 'Text3: ', 'Text4: ', 'Text1: blabla', '\n']
['Text1: 1.00-1; Text3: 2-1.0; Text4: BlaBlaBla;', 'Text2: ', 'Text3: 2-1.0; Text4: BlaBlaBla;', 'Text4: BlaBlaBla;', 'Text1: 1.00-1', ' Text3: 2-1.0', ' Text4: BlaBlaBla', '\n']
WIe man sieht wird hier gar nichts sortiert. :) Mein Ansatz scheint so nicht zu funktionieren
Das Problem das Felder nun doppelt vorkommen wollte ich später angehen, wobei wohl eine Möglichkeit Felder innerhalb einer Liste verschieben zu können dieses Problem gleich lösen könnte...
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich kapiere Dein Ziel noch nicht. Gib doch bitte zur gegebenen Datei einmal die gesuchte Lösung an.

Dazu noch die obligatorischen Fragen: Woher kommt dieses Format? Kannst Du es beeinflussen? Wo soll es später einmal hin? Und könnte man das Zielformat ändern?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
nihilist
User
Beiträge: 28
Registriert: Dienstag 13. Februar 2007, 07:02

Zu der oben eingebundenen Textdatei wäre die Lösung so wie ich sie mir vorstelle:
fett sind hier die Felder die ich ergänzt habe.

Text1: 1.10-1; Text2: misc; Text3: 2-1.0; Text4: BlaBlaBla;
Text1: 1.02-1; Text2: ; Text3: 2-1.0; Text4: BlaBlaBla;
Text1: 1.00-1; Text2: misc; Text3: ; Text4: BlaBlaBla;
Text1: 1.00-1; Text2: ; Text3: ; Text4: BlaBlaBla;
Text1: blabla; Text2: ; Text3: ; Text4: ;
Text1: 1.00-1; Text2: ; Text3: 2-1.0; Text4: BlaBlaBla;
[...]

Die Ursprungsdatei hat das Format:

Code: Alles auswählen

Text1: 1.10-1;
Text2: misc;
Text3: 2-1.0;
Text4: BlaBlaBla;

Text1: 1.02-1;
Text3: 2-1.0;
Text4: BlaBlaBla;
[...]
Ich habe mir die Datei mit awk schon auf einen Datensatz pro Zeile umgewandelt, da ich der Meinung bin/war das ich damit einfacher damit arbeiten kann.
Die einzige Möglichkeit die Ursprungsdatei zu bearbeiten wäre also den "awk-Schritt" wegzulassen. :)

Das ganze soll, wenn in jeder Zeile alle Felder vorkommen eine .csv Datei werden und dann in eine DB importiert werden.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wie kommt es denn dazu, dass Du bei awk nicht alle Zeilen erfasst hast? Wieso entstehen da Lücken?

Anders formuliert: Da wird es ja wohl ein Problem mit der Vollständigkeit geben, oder nicht?

Ich denke das ursprüngliche Format kann man doch sehr einfach mit Python parsen und zu einer CSV konvertieren. Wobei ich ja erwägen würde, direkt SQL-Statements zu bauen, sofern es sich um eine relationale DB handelt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Wie wär's hiermit:

Code: Alles auswählen

import re

scan = re.compile(flags=re.VERBOSE, pattern=r'''
    ( Text \d ) : \s* ( [\w.-]+ ) ;
''').finditer

template = {
    'Text1' : '',
    'Text2' : '',
    'Text3' : '',
    'Text4' : '',
}
with open('test.txt', 'r') as f:
    for line in f:
        data = dict(template)
        for match in scan(line):
            data[match.group(1)] = match.group(2)
        print sorted(data.iteritems())
In specifications, Murphy's Law supersedes Ohm's.
nihilist
User
Beiträge: 28
Registriert: Dienstag 13. Februar 2007, 07:02

Hyperion hat geschrieben:Wie kommt es denn dazu, dass Du bei awk nicht alle Zeilen erfasst hast? Wieso entstehen da Lücken?

Anders formuliert: Da wird es ja wohl ein Problem mit der Vollständigkeit geben, oder nicht?
Ne, da hast du mich falsch verstanden. Mit awk "schreibe" ich den Datensatz auf eine Zeile und entferne die Leerzeile zwischen den Datensätzen. Das nicht alle Felder in allen Datensätzen sind ist schon im Ursprungsfile so und ist nicht durch awk entstanden.
Wenn alle Datensätze alle Felder hätten liese sich das ganze bestimmt auch "nur" mit sed/awk lösen
pillmuncher hat geschrieben: Wie wär's hiermit:
[...]
Ja, das scheint zu funktionieren. Ich brauche etwas Zeit um das zu verstehen und noch ein bischen zu testen und melde mich dann wieder.

Danke an euch zwei! :)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

So gefällt's mir noch besser:

Code: Alles auswählen

with open('test.txt', 'r') as f:
    for line in f:
        data = dict(template)
        data.update(match.groups() for match in scan(line))
        print sorted(data.iteritems())
In specifications, Murphy's Law supersedes Ohm's.
nihilist
User
Beiträge: 28
Registriert: Dienstag 13. Februar 2007, 07:02

Damit komme ich nicht ganz klar.
http://docs.python.org/library/re.html hat geschrieben: re.finditer(pattern, string[, flags])
Return an iterator yielding MatchObject instances over all non-overlapping matches for the RE pattern in string. The string is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result unless they touch the beginning of another match.

Was wäre denn wenn ich in der Textdatei zusätzlich eine URL hätte die ich erfassen will, oder nur Text( mit whitespaces dazwischen)?
Dann. müsste ich doch die regex hier:

Code: Alles auswählen

 \s* ( [\w.-]+ ) ;
erweitern und würde zwangsläufig "overlapping matches" bei den anderen Feldern erhalten und somit würde nichts gematcht werden.

Wäre super wenn du/ihr mir das für diesen Fall kurz aufzeigen könntet, bzw. was mit dem oben zitierten Satz gemeint ist, vielleicht verstehe ich das ja auch ganz falsch :)
Zuletzt geändert von nihilist am Dienstag 24. Mai 2011, 10:02, insgesamt 1-mal geändert.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

nihilist hat geschrieben:Wäre super wenn du/ihr mir das für dieses Fall kurz aufzeigen könntet, bzw. was mit dem oben zitierten Satz gemeint ist, vielleicht verstehe ich das ja auch ganz falsch :)
Nehmen wir an, wir suchen den String 'aa' mit folgendem Code:

Code: Alles auswählen

import re
for match in re.finditer('(aa)', 'aaa'):
    print match.group(0)
Prinzipiell kannst du das gesuchte Muster zwei mal in der Quelle finden. Zeichen 1 und 2 sind allerdings durch den ersten Match bereits verbraucht und so findest du mit regexp den gesuchten String nur einmal. Wäre das ganze "overlapping", dann würdest du die gesuchte Zeichenfolge zwei mal finden, nämlich einmal ab Zeichen 1 und einmal ab Zeichen 2.
Antworten