Suche in Text nach Keywords und speichere restliche Zeile

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
x-herbert

Moin,

folgender Code sucht nach Keywords in einem Text und speichert die Restliche Zeile in einer definierten Form:

Text = body = String:
...
Name : Mayer
Vorname : x-herbert
Email : hier@home.de
EmailNews : Nein
....

Keywords = keymap = Liste: Name,Vorname,Email

Output = output = String: "Vorname","Name","Email","EmailNews"

Code: Alles auswählen

line = body.splitlines()
for key in keymap:
    for i in line:
        regkey = r'(?:^|\s)'+key+r'(?:$|\s)'
        regex = re.compile(regkey)
        result = regex.search(i)
            if result:
                val = i.split(':')[1].strip()	    # Trennen
                output = output.replace(key, val)    # ersetzen der Daten in Vorlage
    output = output.replace(key, "")         # "Löschen" der nicht Ersetzten

hinterher soll der Outputstring z.B. so aussehen:
"x-herbert","Mayer","hier@home.de","Nein"

oder wenn z.B. die eMail-Adresse fehlt:
"Julia","Fröhlich","","Nein"

werden die "Vorgaben" gelöscht (letzte Zeile)

.... ich würde mich über einige Gedankenanstöße freuen, wie man mit Python den Code effektiver/eleganter machen kann

gruss x-herbert
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Moin Moin!
x-herbert hat geschrieben:Moin
Dann wollen wir mal.
Gut wäre erstmal eine formale Beschreibung einer gültigen Schlüssel/Werte-Zeile. Nach Deinem Beipiel würde ich mal tippen:
<ZEILENANFANG><schluessel><LEERZEICHEN><DOPPELPUNKT><LEERZEICHEN><Wert><ZEILENENDE>
wobei <schluessel> aus Buchstaben und vieleicht Zahlen besteht und 'case sensitive' ist.
Die Leerzeichen vor und hinter dem Doppelpunkt sind etwas eigenwillig, aber ich nehme an, dass Du da keinen Einfluss drauf hast. Auf jeden Fall scheinen sie zwingend Bestandteil des Trenners zu sein.

Wenn die obige Definition so stimmt, enthält Dein RegExp Unnötiges. Dort suchst Du ein \s vorm <schlüssel>, aber <schlüssel> wird sicherlich immer am Anfang einer Zeile stehen müssen. Auch Zeilen zu suchen, bei denen unmittelbar hinter <schlüssel> ein Zeilenende ($) kommt, ist unötig, denn ob einem <schlüssel> kein Wert zugewiesen ist oder es den Schlüssel gar nicht gibt, ist für die Auswertung egal. Dagegen würde ich das " : " zwischen Schlüssel und Wert zur zuverlässigen Erkennung zusätzlich heranziehen.
Ein RegExp zur Erkennung einer gültigen Zeile mit (einem bestimmten Schlüssel) könnte dann so aussehen ...
r'^'+key+r' : '
... oder allgemein für auch unbekannte Schlüssel ...
r'^\w+ : ' (ungetestet)

So, das sind nur erstmal meine ersten Ideen. Vielleicht kannst Du noch meine obige Definition bestätigen oder korrigieren.
Jan
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo nochmal!

Ich knalle einfach mal 2 Lösungen hier rein. Ist vielleicht pädagogisch nicht so wertvoll, aber viele lernen ja gerne am Beispiel, ich zumindest.

Code: Alles auswählen

#--------------- Beipieldaten
body = """
Name : Mayer
Vorname : x-herbert
EmailNews : Nein
blablub : tach
asdfasdf
"""

keymap = ("Name","Vorname","Email","EmailNews")

import re,string

#------------------------------ Lösung 1
'''
Das ominöse (?m) ist identisch mit re.MULTILINE und hier nötig, weil man findall() kein re.MULTILINE 
mitgeben kann. Zum RegExp sage ich sonst erstmal nichts :-)  Fremde (oder auch ältere eigene) RegExps 
zu entschlüsseln, ist schon das halbe Vergnügen.
'''
regexp = r"^("  + string.join(keymap,"|") +  r") : (.*)$(?m)"
listResult = re.findall(regexp,body)

print 'r"'+regexp+'"'
print listResult

#------------------------------ Lösung 2
'''
Eine Faustregel: Man sollte RegExps nicht ohne Not verwenden, da sie im Allgemein "teuer" sind. So ein 
RegExp in einer Schleife, die ein paar tausend Mal durchlaufen wird, kann erheblich Zeit kosten. Muss 
man aber von Fall zu Fall abwägen. Hier eine Lösung ohne RegExps (und zudem lesbarer):
'''
dictResult = {}
for line in body.splitlines():
    try:
        (key,value) = line.split(" : ",1)
    except ValueError,e: # wenn es kein " : " gab
        continue
    if key in keymap:
        dictResult[key] = value
        
print dictResult
Ausgabe:
r"^(Name|Vorname|Email|EmailNews) : (.*)$(?m)"
[('Name', 'Mayer'), ('Vorname', 'x-herbert'), ('EmailNews', 'Nein')]
{'Vorname': 'x-herbert', 'EmailNews': 'Nein', 'Name': 'Mayer'}


listResult (eine Listen von Tupeln) oder dictResult (ein Dictionary) musst Du dann nur noch mit der keymap abgleichen, um Deinen gewünschten Output-String zu erzeugen.

Jan
x-herbert

@Voges

Hallo Jan,

mit Deinem Zeilenaufbau
<ZEILENANFANG><schluessel><LEERZEICHEN><DOPPELPUNKT><LEERZEICHEN><Wert><ZEILENENDE>

hast Du vollkommen recht, das Leerzeichen vor und nach dem Doppelpunkt kan man/ich beeinflussen (sieht mit übersichtlicher aus - Geschmackssache..). Vor dem Schlüssel kann u.U. ein Leerzeichen sein, wenn der Name des Webformular-Inputfeldes ausversehen ein Leerzeichen erwischt hat (name=" Name").

Das RegEx zu den teuren "Spielchen" gehört ist mir bekannt - mehrere "inenandergeschachtelte Schleifen" können es aber auch in sich haben - da hift mir nur ein Test... :-)


Die "Schleifenvariante" gefällt mir gut - bleibt "nur noch" die geschickte Umwandlung der Liste bzw. Dict in meinem Ausgabefile. In diesem sind die Anzahl der Zellen (""), Zelltrennungen (,) und "Zellpositionen" festgelegt.

In meiner Variante habe ich in der äußeren Schleife jedes Schlüsselwort aus meiner keymap einzeln angefasst und im Outputstring ersetzt - kann jetzt natürlich die gleiche Schleife basteln...
?? kann man das Ersetzen auch in einem Abwasch machen a la:
"wenn du key aus dict/list in outputstringvorlage findest ersetze mit value ansonnsten lösche key in outputstringvorlage"

Problem ist, wenn der body wie in meinem zweiten Beispiel aussieht (Julia Fröhlich):

Code: Alles auswählen

body = """ 
Name : Fröhlich 
Vorname : Julia
blablub : tach 
asdfasdf 
""" 
soll der Outputsting
"","","Julia","Fröhlich","","" aussehen
vgl. x-herbert
"","","x-herbert","Mayer","","Nein"

(Vorlage zu beiden: "","","Vorname","Name","","EmailNews")

Bei Julia gäbe es keinen key namens EmailNews ...

Gruss & Danke für die Anregungen

x-herbert
x-herbert

=> Nachtrag zu meinem letzten Posting:

die Lösung 2 würde natürlich auch die Zeile

Code: Alles auswählen

blablub : tach 
mit verarbeiten (Lösung 1 muss ich mir noch genauer "reinziehen" ;-])

Wenn "blablub" bei der weiteren Auswertung/Erfassung keine Rolle spielt, wäre das vertane Arbeit... deshalb hatte ich als Ausgangspunkt die keymap gewählt...

Gruss x-herbert
Gast

Hallo!
x-herbert hat geschrieben:Wenn "blablub" bei der weiteren Auswertung/Erfassung keine Rolle spielt, wäre das vertane Arbeit... deshalb hatte ich als Ausgangspunkt die keymap gewählt...
Das if key in keymap: stellt ja sicher, dass nur das ins Dict kommt, was Dich interessiert.
Jan
PS: Gaaanz am Rande: Wie wäre es mal mit registieren? Die Mitgliederanzahl ist immer eine gute Werbung für ein Forum.
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Na toll! Da hat es mich mal wieder unbemerkt rausgeschmissen vorm Absenden ;-)
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

lol... schadenfreude ist ne gemeine Freude, vor allem in solchen Situationen :lol: (sorry@Voges)

danke trotzdem für die Lösung 1, ich hab gerade nach nem ähnlichen Suchmuster gesucht, aber nicht zu dem Thema...
x-herbert
User
Beiträge: 59
Registriert: Mittwoch 27. November 2002, 20:52

@ Gast: ... danke für den Hinweis - nu is meinereiner Registriert....

... das "if key in keymap" ist mir dann auch noch aufgefallen - stimmt...

@ Milan: war ja das Posting bei "Codesnippits" anscheined doch nicht so falsch ;-)
wurde wie von Geisterhand hierher gesendet (ist denke ich auch o.k.)

gruss x-herbert
Antworten