Substring finden und dahinter etwas auslesen

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
Mr. R341
User
Beiträge: 46
Registriert: Dienstag 29. September 2020, 10:51

Hi,

Ich hab eine große Datenbank von 22mb.. egal..

Und in dieser Datenbank gibts Infos. Da will ich nur eine Info raus lesen. Nun steht die Info immer an unterschiedlicher Stelle, ist immer eine andere, aber hat Davor immer das selbe stehen.

Beispiel:

Code: Alles auswählen

data = [
	{"ID" : "1",
	"Rechnung" : "1",
	"Kunde" : "1",
	"Beschreibung"  : "Super hammer tolle geile mega Flatrate von\n02.01.2020 bis 03.01.2020\n hier stehen auch noch tolle dinge",
	"Enddatum" : "0000-00-00"},
	
	{"ID" : "2",
	"Rechnung" : "2",
	"Kunde" : "2",
	"Beschreibung" : "nich so tolle Dienstleistung von\n28.42.2020 bis 03.01.1999\n hier stehen vielleicht andere Dinge",
	"Enddatum" : "0000-00-00"},
]

So... Hier will ich jeweils aus der Beschreibung das Datum, herauslesen und verarbeiten. Jetzt stehen in jeder Beschreibung andere Daten, welche auch nicht immer an der selben stelle sind.
Aber jedes mal habe ich das selbe davor stehen. Im Beispiel das Wort "von\n"

was ich haben will ist in einer for-schleife
"02.01.2020 bis 03.01.2020" und "28.42.2020 bis 03.01.1999"
zum weiter verarbeiten...

Wie komme ich nun da ran?

ich hatte überlegt:

Code: Alles auswählen

for x in data:
	substring = "von\n"

	if x["Beschreibung"].find(substring):
#		date = something[:24] after substring

Jetzt ist nur die Frage, wie ich das in die Variable bekomme.

Danke für eure Hilfe :wink:
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Die find-Funktion liefert Dir ja die Stelle, an der der Such-String gefunden wird. Das kannst du zum Ausschneiden nehmen.

z.B so:

Code: Alles auswählen

test_string = "nich so tolle Dienstleistung von\n28.42.2020 bis 03.01.1999\n hier stehen vielleicht andere Dinge"
search_string = 'von\n'
if search_string in test_string:
    letter_count = test_string.find(search_string)
    date_string = test_string[letter_count:letter_count+29]
Mr. R341
User
Beiträge: 46
Registriert: Dienstag 29. September 2020, 10:51

Funktioniert... vielen Dank..

Aber wieso funktionierts? :D Ich verstehe nicht, was letter_count ist
Nufnus
User
Beiträge: 18
Registriert: Sonntag 29. November 2020, 21:40

Mr. R341 hat geschrieben: Dienstag 1. Dezember 2020, 20:26 Aber wieso funktionierts? :D Ich verstehe nicht, was letter_count ist
Das ist die Position wo der search_string im Text beginnt. Und von da an schneidet er dann noch weitere 29 Zeichen "raus" und setzt damit einen neuen string zusammen.
Wie er geschrieben hat: find() liefert die Stelle, an der der Such-String gefunden wird.

Übrigens das das du da hast ist ein JSON String, oder? :)
Benutzeravatar
snafu
User
Beiträge: 6850
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich würde da mit regulären Ausdrücken arbeiten, dann hätte man es genauer.

Code: Alles auswählen

import re

def parse_date_range(string):
    date_re = r"\d{2}\.\d{2}\.\d{4}"
    range_re = rf"von\n({date_re}) bis ({date_re})"
    match = re.search(range_re, string, re.MULTILINE)
    if not match:
        raise ValueError("Could not parse dates")
    return match.groups()

def main():
    test_strings = [
        "Super hammer tolle geile mega Flatrate von\n02.01.2020 bis 03.01.2020\n hier stehen auch noch tolle dinge",
        "nich so tolle Dienstleistung von\n28.42.2020 bis 03.01.1999\n hier stehen vielleicht andere Dinge"
    ]
    for string in test_strings:
        print(parse_date_range(string))

if __name__ == "__main__":
    main()
Ansonsten mit ein paar zusätzlichen Annahmen und Bordmitteln:

Code: Alles auswählen

def parse_date_range(string):
    for line in string.splitlines():
        if line[:2].isdigit() and line[-4:].isdigit():
            return line.split(" bis ")
    raise ValueError("Could not parse dates")
Ist nur etwas fragiler. Wenn man das weiter ausarbeitet, dann baut man letztlich die Funktionalität des gezeigten regulären Ausdrucks nach...

EDIT:
Das re.MULTILINE-Flag kann man auch weglassen, kommt nämlich aufs selbe raus.
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Mr. R341 hat geschrieben: Dienstag 1. Dezember 2020, 20:26 Aber wieso funktionierts? :D Ich verstehe nicht, was letter_count ist
<str>.find() gibt die Position des ersten Zeichens in String zurück. Und die Zahl nehme ich als Startpunkt für das Ausschneiden des gewünschten Bereichs.

<ganzer_string>[start:ende]
Benutzeravatar
__blackjack__
User
Beiträge: 14005
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bolitho: Dein Code durchsucht unnötigerweise zweimal. Erst sucht das ``in`` ob die Zeichenkette enthalten ist und dann sucht `find()` noch mal nach der Zeichenkette. Man kann auch nur einmal den Index suchen und dann entsprechend reagieren falls nichts gefunden wurde. Ich würde auch `index()` bevorzugen und die Ausnahme behandeln statt `find()` mit dem Sonderwert der aber ein gültiger Index ist. Damit passieren leichter mal Unfälle.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Danke für den Hinweis, __blackjack__!

Das wäre dann in etwa so:

Code: Alles auswählen

test_string = "nich so tolle Dienstleistung von\n28.42.2020 bis 03.01.1999\n hier stehen vielleicht andere Dinge"
search_string_successful = "von\n"
search_string_unsuccessful = "nicht im Text"


def find_substring(test_string, search_string):
    try:
        letter_count = test_string.index(search_string)
        return test_string[letter_count:letter_count + 29]
    except ValueError:
        return None


print(find_substring(test_string, search_string_successful))
print(find_substring(test_string, search_string_unsuccessful))
Antworten