String manipulation - Ideen / Vorschläge für das Problem

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
gabber

Hallo zusammen,

ich bin neu im Forum also habt bitte Rücksicht falls ich was falsche mache. Ich versuche mal mein Problem so genau wie möglich zu beschreiben.

Ich möchte ein altes DOS-Programm neu entwickeln. Das DOS-Programm stellt nichts anderes wie eine "Literaturdatenbank" dar. Es gibt eine DBF-Datei wo Daten gespeichert sind und eine Textdatei. In der DBF-Datei stehen allerdings nur Kürzel + Seiten, in der Textdatei das Kürzel + Buchtitel, Autor etc.
Mal ein kleiner Auszug das es vielleicht klarer wird was ich meine:
DBF-Datei:
  • AMO IV/43(ÖK)
    Ale.2a/S.97
    Ale.8 Par.35
    B 32/1(2010),S.65(F,ANM)
    BC 8
    BdB 2/347
    Boll.Trento 47/3(2004),S.42(CF)
    C 262
    Coolia 21/4,Titels.(SF)
    Cou.1669
    D 59
    D93/80+81
    End./PFU,S.421(B,CF)
    ...
In der Textdatei entsprechend dann so etwas::
  • Ale. = Alessio: Fungi Europaei II, Boletus (1985)
    Ale.2a = Alessio: Fungi Europaei IIa, Boletus supp.
    B = Zeitschrift "Boletus" herausgegeben vom Kulturbund der DDR als Arbeitsmaterial Mykologie
    C = B.Cetto: Der grosse Pilzfuehrer (I - IV) und: I funghi dal vero (V - VII)
    ...
Ich hab es mittlerweile soweit das die Daten in aus der DBF in einer Liste gespeichert werden genau so die Daten aus der Textdatei als Beispiel wieder:

Code: Alles auswählen

dbf_list = ['Ale.2a/S.97', 'Ale.8 Par.35', 'BC 8', 'B 32/1(2010),S.65(F,ANM)']
text_list = [['Ale.', 'Alessio: Fungi Europaei II, Boletus (1985)'], ['Ale.2a', 'Alessio: Fungi Europaei IIa, Boletus supp.']]
Jetzt möchte ich natürlich die Daten aus der dbf_list mit dem richtigen Name aus der text_list ersetzen. Was ja an sich auch nicht so schwer wäre wenn eine eindeutige Kennung vorliegen würde, was aber hier nicht der Fall ist (oder ich zu kompliziert denke). Als Beispiel:

Ich habe den Eintrag "Ale.2a/S.97" jetzt schau ich in die text_list und finde hier "Ale." und "Ale.2a". Wenn ich jetzt die replace Funktion von strings nutze dann nimmt er natürlich den Wert "Ale." ich möchte aber immer genau den Namen nur verwenden wenn dieser auch identisch mit dem Anfang ist.

Ich hoffe ich konnte erklären was ich möchte. Hier noch meine Spaghetti Funktion wo ich bisher nur probiert habe. Verzeiht mir bitte die schlechte Namensgebung.

Code: Alles auswählen

def literature(dictionary, test):
    for record in dictionary:
        if record['CODE'] == 'gpx':
            string = record['LITERAT']
            technicalLiterature = str(string)
            start = technicalLiterature.find("Literatur: ") + len("Literatur: ")
            end = technicalLiterature.find('Schluessel', start)
            technicalLiterature = technicalLiterature[start:end]
            # format string and remove unused parameter

            technicalLiterature = technicalLiterature.lstrip()
            technicalLiterature = technicalLiterature.replace('\n', '')
            technicalLiterature = technicalLiterature.replace('\r', '')
            technicalLiterature = technicalLiterature.replace(' - ', ' -')
            technicalLiterature = technicalLiterature.replace(' - ', ' -')
            technicalLiterature = technicalLiterature.replace('ì', '')
            technicalLiterature = technicalLiterature.rstrip(" -")
            #myTechnicalLiterature = myTechnicalLiterature.rstrip("-")

            array = re.split(r"\ -", technicalLiterature)

            for i in sorted(array):
                i = i.replace('\r', '')
                i = i.lstrip()
                item = [item[0] for item in test]
                item2 = [item[1] for item in test]
                print(i)
                for number, blubb in enumerate(item):
                    gab = i[:10]
                    if blubb in gab:
                        gab = gab.replace(blubb, item2[number])
                        print(gab)
                        #if len(blubb) > 2:

            print(test)
ElektroBerry
User
Beiträge: 31
Registriert: Samstag 16. Mai 2020, 18:52

Wenn wirklich nichts anderes möglich ist, kann man versuchen die Ähnlichkeit der Abkürzungen zu vergleichen:

Code: Alles auswählen

from difflib import SequenceMatcher

dbfs = ['AMO IV/43(ÖK)', 'Ale.', 'Ale.2a/S.97', 'Ale.8 Par.35', 'B 32/1(2010),S.65(F,ANM)',
        'BC 8', 'BdB 2/347', 'Boll.Trento 47/3(2004),S.42(CF)', 'C 262',
        'Coolia 21/4,Titels.(SF)', 'Cou.1669', 'D 59', 'D93/80+81', 'End./PFU,S.421(B,CF)']
texte = {'Ale.':'Alessio: Fungi Europaei II, Boletus (1985)', 'Ale.2a': 'Alessio: Fungi Europaei IIa, Boletus supp.'}


def give_highest_similarity(dbf, texte):
    similaritys = []
    for text_item in texte:
        similarity = SequenceMatcher(None, dbf, text_item).ratio()
        similaritys.append({"similarity": similarity*100, "items": [dbf, text_item]})
    similaritys = sorted(similaritys, key=lambda k: k["similarity"])
    if similaritys[-1]["similarity"] > 60:
        return similaritys[-1]
    else:
        return False


for dbf in dbfs:
    highest_similarity = give_highest_similarity(dbf, texte)
    if highest_similarity:
        print(f"dbf: {dbf}")
        print(f"Ähnlichkeit: {highest_similarity['similarity']}")
        print(f"Output: {highest_similarity['items'][1]}: {texte[highest_similarity['items'][1]]}\n")
Zizibee
User
Beiträge: 229
Registriert: Donnerstag 12. April 2007, 08:36

Kannst du nicht deine "text_list" nach der Länge deines ersten Eintrags sortieren? Von lang zu kurz.
Dann würdest du zuerst nach 'Ale.2a' suchen und ersetzen und dann erst nach 'Ale.'
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Würde ich auch so wie Zuzubee machen. Die Keys aus der Textdatei nach Länge absteigend sortieren.
Dann brauchst du keine regulären Ausdrücke sondern kannst mit normalen Zeichenkettenoperationen arbeiten. Ein einfaches "in" um zu sehen, ob die Zeichenkette enthalten ist und ein "replace" um sie zu ersetzen.
nezzcarth
User
Beiträge: 1764
Registriert: Samstag 16. April 2011, 12:47

Mal eine Rückfrage: Wie funktioniert in dem alten DOS-Programm denn die Zuordnung? Aus meiner Sicht ist eine Datenbank, deren Elemente man nicht eindeutig zuordnen kann, im Grunde als defekt zu betrachten. Wenn das so ist, würde ich davon abraten, weitere Einträge zu erfassen und bei deinem neuen Versuch (für den sich z. B. sqlite anbietet) darauf achten, dass es Primärschlüssel gibt. Eine Datenbank, aus der man seine Daten nur mit großen Aufwand abfragen kann, erfüllt ihr Aufgabe eigentlich nicht. Um wie viele Datensätze, die zugeordnet werden müssen geht es denn?

Bei deinem Code-Beispiel habe ich Schwierigkeiten zu verstehen, was da überhaupt passiert/passieren soll. In Zeile 2 z. B. iterierst du über die Schlüssel eines Wörterbuchs, in Zeile drei verwendest du das dann wie ein Dictionary; das kann nach meinem Verständnis eigentlich gar nicht funktionieren (wenn ich nichts übersehe).
gabber

Danke erstmal für die Ideen und eure Hilfe.

@ElektroBerry ich werde mir dein Code in Ruhe noch anschauen und testen. Danke dafür schon einmal.
@Zizibee das mit dem sortieren nach Länge ist eine gute Idee hab ich irgendwie nicht im Kopf gehabt. Werde ich auch auf alle Fälle testen.
@nezzcarth ich hol mal ein bisschen weiter aus:

Das alte DOS-Programm ist für Pilzkartierung gedacht und dient als Naschlagewerk für Pilzarten inklusive Literatur. Es gibt mehrere DBF-Dateien. In einer Datei sind Pilze hinterlegt, in einer zweiten die Synonyme und in einer dritten die Literatur.
Folgende Felder möchte ich aus der Pilze-DBF entnehmen:
  • Satznummer:
    Familie:
    Vollname:
    Gattung:
    Gruppe:
    Roteliste:
Folgendes möchte ich aus der Synonyme-DBF entnehmen:
  • Satznummer:
    Vollname:
    Gültige Art:
In der Literatur-DBF möchte ich folgendes entnehmen:
  • Satznummer:
    Literatur:
Anhand dieser Daten möchte ich eine SQLite Datenbank aufbauen. Wenn jemand dazu eine gute Idee hat wie diese aussehen könnte nur her mit, denn darüber hab ich mir aktuell noch keine Gedanken gemacht da ich erst testen möchte wie ich an die ganzen Daten komme.

Wenn ich in dem alten DOS-Programme einen Literatureintrag machen möchte erhalte ich nichts anderes wie ein Texteditor :lol: . Derjenige der die Einträge mit der Literatur gemacht hat, hat leider nichts dabei gedacht und immer unterschiedliche Kürzel verwendet, so dass kein "System/Trend" erkennbar ist. Die Kürzel wiederum stehen in einer 'literat.txt' da steht dann wie schon beschrieben sowas drin:

'Ale. = blabla'
Ale.2a = blablab'
...

Und wenn ich jetzt natürlich das Kürzel durch den vollen Textnamen ersetzen möchte dann nimmt er natürlich das 'Ale.' und nicht das 'Ale.2a'.

Ist leider echt doof das es keine Struktur unter den Daten gibt (zumindest bei der Literatur). Vielleicht hilft es dir die "Rohdaten" zusehen von einem Pilzliteratureintrag.

Code: Alles auswählen

def literature(dictionary, test):
    for record in dictionary:
        if record['CODE'] == 'gpx':
            string = record['LITERAT']
            print(string)
            
# Hier die Ausgabe von print(string)

 Literatur: Lassoe & Petersen Band 1 S.769 -
 Kbch.54 -MH I/153 -Ha.1 -SPT I/33 -PD 39+41 -C 262 -NGB 45
 Sing.VI/2,1-9 -Md.60 -D 59 -P 193 -Horak 133 -P.d.UdSSR/28 -Ge.II/46
 Schl.Wvg.II/41 -Grue.203 -Eng.II/41 -K 29 -End./PFU,S.421(B,CF) -Ale.8
 Par.35 -AMO IV/43(ÖK) -Sv.223 -PDS III/8 -Gl.181 -Pätz.80 -Gmi.72+74 -
 D93/80+81 -BC 8 -Cou.1669 -Schm/Helf.131 -MA 18938(B,D) -Laux,S.14+80
 T 1997/2.S.45(CF) -MA 22528(SZ) -SWPR 1998/2,S.61(CF,Rezepte) -
 T 1998/4,S.19(CF) -Ale.2a/S.97 -Krglst.2/245(CF) -MA 23680(ANM)
 T 30(2002/1),S.46(Missbildg.,CF) -T 33(2002/4) S.44(CF) -LauxAtl,S.30
 T 45(2005/4),S.38(CF) -T 46(2006)/S.78(CF) -Coolia 21/4,Titels.(SF) -
 Riv.d.Mic.44/2(2001),S.106(ANM,CF) -Riv.d.Mic.39/2(1996),S.156(CF) -
 T 47(2006),S.31(CF) -Boll.Trento 47/3(2004),S.42(CF) -Gmi/Boe 18 -
 Lüd.,S.17(CF)+28(CF)+46(CF)+(147+166+358(CF) -T 51(2007/2),S.76(CF) -  ì
T 52(2007),S.8(CF) -T 55(2008),S.20(CF,ANM) -T 54(2008),S.55(ANM,CF) -
 BdB 2/347 -Gerh.(BLV),S.466 -T 60(2009/3),S.25+35+68(CF) -FN S.168 -
 T 64(2010),S.27(ANM,CF) -B 32/1(2010),S.65(F,ANM) -T 68(2011),S.56(CF)
 ZfM 78/1(2012),DGfM-Mitt.S.20(TOX bei Standort unter Taxus) -
 T 72(2011),S.95(Pilzschwemme) -T 73(2011/6),S.52(ANM,CF) -
 T 74(2012/1),S.69(CF) -T 76(2012)/S.76(Herst.+Verw.v.Pilzpulver,CF) -
 ZfM 79/1(2013),S.228(TOX nach mehrmaligem Aufwärmen) -
 T 84(2013/5),S.82(ANM,CF) -T 85(2013/5),S.66(CF,ANM) -
 T 88(2014),S.61(CF)+91(CF,ANM) -T 93(2015/2),S.70(CF) -
 ZfM 2015/1 S.130(F,ANM) -T 94 (2015/3),S.28(CF) -T 109(2017/5)S.59(CF)
 ZfM 2017/1,S.61(CF,F-Baikalgebiet) -T 112 (2018/2),S.9(CF) -
 T 96(2015/5),S.63+66(CF) -MB 16(2015),S.22(TAX,CF) -
 T 99(2016/2),S.95(giftige Knollis in Kaufland-Steinpilzen) -
 T 112 (2018/2),S.9+24(ANM,CF) -T 120 2019/4,S.3+73(CF,ÖK) -
 T 111 2018/1,S.10(ANM,CF) -MB 20(2020)S.3(CF,ANM) -
 T 124(2020),S.37(ANM,CF) -
 ssp.trisporus: MA 23873(ANM,D,MZ) -MB 17(2016),S.79(CF,TOX) -

 Schluessel-Sammlung: 29/9a -30/2a -239/18a -

 KB-Dias:  179 - 180 - 181 -
 6x6-Dias: 57 - 689 - 690 -
 Bilddateien: 008boedu.jpg (BC) * boeduli2.jpg (Bollm.) *

 Anmerkg.:
Ich versuche letztendlich alles zwischen 'Literatur:' und 'Schluessel' zu bekommen, formatieren und entsprechend das ganze in einer Liste hinzuzufügen um es später in eine SQLite Datenbank zu konvertieren. Dabei sollen allerdings die Kürzel durch die Original Büchernamen ersetzen werden und hier scheiter ich da ich z.B den Eintrag 'Ale.2a/S.97' und in meiner 'Literat.txt' aber die Einträge 'Ale.' und 'Ale.2a' habe und wenn ich jetzt einfach durch ein 'replace' das ersetzen möchte nimmt er natürlich das falsche.

Zu der Größe der Daten wir reden hier von fast 35 000 Pilzarten die in der Pilz-DBF Datei enthalten sind, dabei hat jeder einzelne Pilz seine Literatur hinterlegt in der Literatur-DBF allerdings nur mit Kürzel und nicht mit vollem Buchname und die Kürzel wiederum bekommt man aus einer Literat.txt. Jeder Eintrag in der Pilz-DBF hat natürlich seine eigene Satznummer, ein eindeutiger Code im Beispiel oben wäre das der Pilz mit der Satznummer 'gpx'.

Ich mein vielleicht gibts auch besere Ideen / Ansätze um die Daten zu verarbeiten. Ich bin für jeden Tipp dankbar und werde sie auch versuchen.

Grüße Gabber
Benutzeravatar
__blackjack__
User
Beiträge: 14054
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@gabber: Wenn das offensichtlich unstrukturierter Freitext ist aus Sicht des Programms, dann geht nur eine Unterstützung durch Software, das heisst eine ”geratene” Zuordnung die aber auf jeden Fall noch mal von einem denkenden Wesen kontrolliert werden muss.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
gabber

Danke für eure Hilfen. Mir bleibt wohl nichts anderes übrig als das ganze manuell umzupflegen.
Antworten