 |
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 23.04.2022, 20:36 Titel: Keyfiles |
|
|
In der Applikation die wir Anfang der 80er Jahre entwickelten gab es Dateien bei denen man direkt auf einen bestimmten Datensatz zugreifen musste. Das war z.B. der Artikelstammsatzfile aus dem man mit der Artikelnummer oder auch der Kundenstammsatzfile. direkt den Stammsatzrecord eingelesen bzw, gespeichert hat.
Wir hatten damals 2 Zugriffsarten (die zugehörigen Functions haben wir damals von unserer beraterfirma erhalte, wir brauchten sie nur anwenden.).
Wir hatten damals 2 Möglichkeiten für den direkten Zugriff auf Records:
1) IAM=Index Access Method: dazu gaben wir der Funktion nur die Artikelnummer bekannt und erhielten über einen Keyfile den gesuchten Record. Mit welchem Algorithmis die Funktion arbeitete weiß ich nicht mehr.
2) ISAM=Index Sequential Access Method: ich weiß noch, dass der keyfile dafür sortiert war und zwischen Einträgen Lücken hatte indie bei Neuanlage eines Datensatzes die neuen Einträge gemacht wurde. War eine Lücke aufgebraucht wurde der Keyeintrag ans Ende des Keyfiles gestellt und mittesl Pointer zugeordnet. Daher musste man diese Keyfiles auch von Zeit zu Zeit neu erstellen.
Wir hatten damals sowohl für die Erstellung der Keyfiles als auf für die Zugriife auf die Datenfiles über einen Keyfile eigene Funktionen. Damit war der direkte Zugriff auf bestimmte Records für uns sehr einfach zu programmieren.
Gibt es derartige oder ähnliche Hilfsmittel auch für FreeBasic? _________________ Grüße
kilix |
|
Nach oben |
|
 |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1153 Wohnort: Ruhrpott
|
Verfasst am: 24.04.2022, 15:27 Titel: |
|
|
Für konkrete Vorschläge sind deine Angaben etwas zu vage, aber sicher lässt sich das alles auch in FB programmieren.
Allerdings stammen die von dir beschriebenen Vorgehensweisen aus einer Zeit, als Arbeitsspeicher in Kilobyte, Festplattengrößen in Megabyte und Prozessortakte in Megahertz angegeben wurden, von Multicoreprozessoren ganz zu schweigen. Bei heutigen Geräten fällt das Umkopieren einer 1 oder 2 Megabyte großen Datei kaum noch ins Gewicht, und wenn es sich nicht um riesige Dateien handelt, ist es meistens sinnvoller, zum Bearbeiten die gesamte Datei in den Arbeitsspeicher zu laden und danach wieder zurückzuschreiben.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 24.04.2022, 15:35 Titel: |
|
|
Ok, ist klar die Zeit und die Technologie hat sich stark verändert!
Mir ist aber jetzt ganz konkret eines nicht klar: ist es heute sinnvoller eine Datei von fast 30.000 Datensätzen sequentiell durchzulesen, um einen bestimmten Datensatz einzulesen und bearbeiten zu können?
Ich hab natürlich schon bemerkt, dass die Verarbeitung auf meinem Rechner sehr schnell ist, ich hab aber auch einen relativ schnell Desktop-PC aber wie sieht das auf einem langsamen Laptop aus? _________________ Grüße
kilix |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4531 Wohnort: ~/
|
Verfasst am: 24.04.2022, 19:54 Titel: |
|
|
Du musst ja nicht sequenziell einlesen - du kannst auch ganze Blöcke einlesen.
Allerdings kiingt mir die Aufgabenstellung so, als ob man da einen Datenbankeinsatz geplant hat. Ein Datenbanksystem kann man mit FreeBASIC auf jeden Fall auch programmieren, aber da ist es einfacher (und sicherer), auf die bereits bestehenden zurückzugreifen. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 24.04.2022, 20:25 Titel: |
|
|
Nachdem ich noch aus den Urzeiten der EDV stamme habe ich 2 Fragen:
1) wie liest man ganze Blöcke ein?
2) welche Datenbanksysteme gibt es auf die man zurückgreifen kann?
Ich denke zwar nicht, dass ich für meine Anwendung ein Datenbanksystem brauche. Nachdem die Vereine und die Mitglieder so nummeriert sind, dass die ID ident mit der Satznummer ist kann ich so ganz einfach direkt zugreifen. Ich musste mir nur eine Zwischendatei (Keyfile) schaffen und vom Verein zu seinen Mitgliedern zu kommen. So gesehen ist es doch noch relativ einfach. Mir geht es aber auch darum das Umfeld von FreeBasic etwas zu verstehn. _________________ Grüße
kilix |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4531 Wohnort: ~/
|
Verfasst am: 24.04.2022, 21:08 Titel: |
|
|
Hier die Bibliotheken, die FreeBASIC "von Haus aus" unterstützt (also zu denen es auch bereits passende Header-Dateien gibt:
https://www.freebasic-portal.de/befehlsreferenz/externe-bibliotheken-639.html
Unter den Datenbanken ist genannt: GDBM, MySQL,PostgreSQL und SQLite.
Zum Einlesen ganzer Datenblöcke habe ich hier gerade einen Code herumliegen, der das mit einem selbstdefinierten Datentyp macht.
Code: | DIM AS INTEGER dateiNr = FREEFILE
TYPE T2DPunkt
AS DOUBLE x, y
AS STRING*1 bezeichner
DECLARE CONSTRUCTOR
DECLARE CONSTRUCTOR(x_ AS DOUBLE, y_ AS DOUBLE, bez as STRING)
END TYPE
CONSTRUCTOR T2DPunkt ' leerer Standardkonstruktor
END CONSTRUCTOR
CONSTRUCTOR T2DPunkt(x_ AS DOUBLE, y_ AS DOUBLE, bez as STRING)
x = x_
y = y_
bezeichner = bez
END CONSTRUCTOR
' Speicher reservieren und Daten anlegen
DIM AS T2DPunkt PTR speicherAlt = CALLOCATE(3, SIZEOF(T2DPunkt))
DIM AS T2DPunkt PTR punktA = NEW (speicherAlt) T2DPunkt( 3, -1.5, "A")
DIM AS T2DPunkt PTR punktB = NEW (speicherAlt+1) T2DPunkt( 5.1, 0, "B")
DIM AS T2DPunkt PTR punktC = NEW (speicherAlt+2) T2DPunkt(-2, 4.8, "C")
OPEN "temp_speicher.sav" FOR BINARY ACCESS WRITE AS #dateiNr
PUT #dateiNr, 0, *speicherAlt, 3
CLOSE #dateiNr
' weiteren Speicher reservieren und Daten laden
DIM AS T2DPunkt PTR speicherNeu = CALLOCATE(3, SIZEOF(T2DPunkt))
DIM AS T2DPunkt PTR punktX = NEW (speicherNeu) T2DPunkt
DIM AS T2DPunkt PTR punktY = NEW (speicherNeu+1) T2DPunkt
DIM AS T2DPunkt PTR punktZ = NEW (speicherNeu+2) T2DPunkt
OPEN "temp_speicher.sav" FOR BINARY ACCESS READ AS #dateiNr
GET #dateiNr, 0, *speicherNeu, 3
CLOSE #dateiNr
' Ausgabe des dritten Punktes; aufraeumen und beenden
PRINT punktZ->bezeichner & "(" & punktZ->x & "/" & punktZ->y & ")"
DEALLOCATE speicherAlt
DEALLOCATE speicherNeu
SLEEP |
Wobei es in deinem Fall vielleicht noch besser über ein Array ginge, weil du dann mit Array-Index direkt auf das passende Element zugreifen kannst. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 26.04.2022, 20:00 Titel: |
|
|
danke nemored, für die ausführliche Information. Was den Code betrifft muss ich ihn erst "verdauen", da sind einige Befehle etc. enthalten mit denen ich noch nichts zu tun hatte. Dafür brauche ich noch Zeit!
Bis jetzt habe ich den Vorteil, dass mir das Vorsystem aus dem ich die Daten hole für alle Dateien IDs mit gibt die ident mit den Satznummern sind. Damit kann ich in vielen Fällen direkt auf den gewünschten Satz zugreifen.
In einem Fall ist das nicht möglich: wenn ich auf ein Mitglied in einem Verein zugreifen will geht das direkt nicht. Daher habe ich eine Keyfile erstellt der als erstes Feld die Vereinsnummer und als zweites die MitgliederID enthält. Damit kann ich direkt auf alle Mitglieder dieses Vereins (sequentiell) zugreifen. Wenn ich zusätzlich zur Vereinsnummer ein paar Anfangsbuchstaben des Namens habe bin ich mist schon beim richtigen Mitgliedersatz andernfalls muss ich zwischen 2-5 Sätzen wählen. Da gibt es absolut kein Problem mit der Geschwindigkeit.
Ich bin aber ständig auf der Suche mich zu verbessern und daher für jeden Hinweis und jede Anregung dankbar! _________________ Grüße
kilix |
|
Nach oben |
|
 |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1153 Wohnort: Ruhrpott
|
Verfasst am: 27.04.2022, 16:10 Titel: |
|
|
Bei der heutigen Rechnergeneration brauchst du solche Klimmzüge nicht mehr.
Du kannst jeden Datensatz in einen passenden UDT packen und die ganze Datei als Array in den Arbeitsspeicher laden. Ich habe dir mal ein kleines Demoprogramm geschrieben, um zu zeigen, was heutzutage und mit FB möglich ist.
Es erstellt eine Datei mit 30000 Einträgen und schreibt sie auf die Festplatte, liest sie dann in ein Array ein, in dem du anschließend nach einem Namen suchen kannst (nur als Beispiel). Der Name lautet immer "Meier", gefolgt von dem Index, ohne Leerstelle. Das Programm durchsucht das Array von vorne, bis es den gesuchten Namen findet, der letzte Name ist "Meier30000". Das geht so schnell, daß du auf Indexdateien und ähnliches verzichten kannst.
Und keine Panik, wenn du nicht alles auf Anhieb verstehen solltest, speziell das Speichern und Lesen der Datensätze mittels eines eigenen UDTs und UNION ist ein einigermaßen tiefer Griff in die Trickkiste.
Code: | Type tDatensatz Field = 1
As ULong mitgliedsnummer
As String*40 Name
As String*40 vorname
As ULong plz
As String*40 wohnort
As Byte dummy
End Type
Type tZumSpeichern Field = 1
Union
datensatz As tDatensatz
datensatz_ As String*SizeOf(tDatensatz)
End Union
End Type
Dim As Integer x
Dim As String suchname
Dim As tDatensatz datensatz
Dim As tZumSpeichern speichern
'Datei mit 30000 Einträgen erstellen
Open ExePath + "\datei.dat" For Output As #1
For x = 1 To 30000
With datensatz
.mitgliedsnummer = x
.name = "Meier" + Str(x)
.dummy = 255
End With
speichern.datensatz = datensatz
Print #1, speichern.datensatz_;
Next
Close 1
'datei in array einlesen
Open ExePath + "\datei.dat" For Binary As #1
ReDim As tDatensatz datenarray(0)
x = 1
Do
speichern.datensatz_ = Input(SizeOf(tZumSpeichern) - 1, #1)
ReDim Preserve datenarray(x)
datenarray(x) = speichern.datensatz
x += 1
Loop Until Eof(1)
Close 1
'name im array suchen
Do
Input "nach Namen suchen"; suchname
If suchname = "" Then
Exit Do
EndIf
For x = 1 To UBound(datenarray)
With datenarray(x)
If .name = suchname Then
Print "Name gefunden: ";.name
Print "Mitglidsnummer: ";.mitgliedsnummer
Print
Exit For
EndIf
End With
Next
If x = UBound(datenarray) + 1 Then
Print "Name nicht gefunden"
EndIf
Print
Loop
|
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 27.04.2022, 17:06 Titel: |
|
|
Hallo grindstomne und nemored!
Da habt ihr euch viel Arbeit für mich gemacht! Ich bin von den Möglichkeiten beeindruckt, das wäre damals nie so möglich gewesen!
Da kann ich in meinem Konzept einiges vereinfachen!
Das führt mich gleich zu einer neuen Frage: das Problem habe ich zwar gelöst aber ich denke, dass es schneller gehen müsste.
Es handelt sich um eine Tabelle, die ca. 1500 Elemente mit einer Länge von String * 8 enthält. Der Sort dauert so ca. 5 Minuten. Wenn ich vergleiche, dass das Einlesen der Input-Datei mit ca. 440.000 Sätzen und das Erstellen der Sorttabelle keine 15 Sekunden dauert ist das eine Ewigkeit.
Ich kann mir nur vorstellen, dass mein Sort (Bubble-Sort) sehr langsam und die Daten sehr bunt gemischt sind, so dass sehr viel herumgeswapt werden muss.
Gibt es dafür schnellere Sort-Codes? _________________ Grüße
kilix |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4531 Wohnort: ~/
|
Verfasst am: 27.04.2022, 21:30 Titel: |
|
|
Sehr effektiv ist Quicksort, der Algorithmus ist aber nicht so leicht zu durchdringen.
Code: | sub quicksort(a() as string, byval s as integer = 0, byval e as integer = -1)
if s = 0 then s = lbound(a)
if e = -1 then e = ubound(a)
dim as integer i = s, j = e
dim as string mitte = lcase(a((i+j)\2))
do
while lcase(a(i)) < mitte : i += 1 : wend
while lcase(a(j)) > mitte : j -= 1 : wend
if i <= j then
swap a(i), a(j)
i += 1
j -= 1
end if
loop until i > j
if j > s then quicksort(a(), s, j)
if i < e then quicksort(a(), i, e)
end sub |
Das ist jetzt rein für Strings; zum Sortieren von UDTs muss die Vergleichsoption entsprechend angepasst werden. Es gibt aber auch eine Implementierung in der C-Runtime, die wahrscheinlich theoretisch empfehlenswert ist (weil universell einsetzbar), aber für die man sich ein wenig in Callback-Funktionen einarbeiten sollte.
Noch effektiver sind gut aufgebaute Suchbäume, aber das würde ich schon als deutlich fortgeschrittene Technik bezeichnen. Da geht es dann nicht nur um das Verwalten bestehender Datensätze, sondern um den effektiven Aufbau der kompletten Datenstruktur.
@grindstone
Zu deinem Array-Beispielen: Hast du mal NEW[] mit Angabe der Startadresse versucht? Das müsste sich eigentlich sehr elegant machen lassen; mir fehlt nur gerade die Zeit zum experimentieren ... _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 27.04.2022, 21:49 Titel: |
|
|
Danke für den Code, ich werde ihn probieren!
In der Zwischezeit habe weiterprobiert und auch im Internet gesucht. Nach irgend einem Satz den ich gelesen habe kam mir der Verdacht, dass mein Sort deshalb so langsam sein könnte weil ich eine Stringtabelle sortiere. Ich habe dann den Sortbegriff (es sind die Mitgliedernummer und ein 2stellieger Zahlencode) so zusammengestellt, das ein Integerwert (ULONG) entstand. Damit hatte ich eine Integertabelle und nun dauerte der Sort kaum mehr als 20 Sekunden statt fast 5 Minuten und das ist akzeptabel.
Trotzdem werde ich den Quicksort auch genauer ansehen! _________________ Grüße
kilix |
|
Nach oben |
|
 |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1153 Wohnort: Ruhrpott
|
Verfasst am: 30.04.2022, 19:59 Titel: |
|
|
Du hast an anderer Stelle erwähnt, daß deine Dateien im CSV-Format vorliegen. Die Funktionen zum Lesen und Schreiben dieses Formates lassen sich direkt in den UDT integrieren. Ich habe mein kleines Beispielprogramm von oben mal entsprechend umgeschrieben. Damit kannst du jetzt auch Strings mit variabler Länge verwenden.
Code: | Type tDatensatz
As ULong mitgliedsnummer
As String Name
As String vorname
As ULong plz
As String wohnort
Declare Sub speichern(dateinr As ULong)
Declare Sub lesen(dateinr As ULong)
End Type
Sub tDatensatz.speichern(dateinr As ULong)
With This
Print #dateinr, mitgliedsnummer; ","; _
Name; ","; _
vorname; ","; _
plz; ","; _
wohnort
End With
End Sub
Sub tDatensatz.lesen(dateinr As ULong)
With This
Input #dateinr, mitgliedsnummer
Input #dateinr, Name
Input #dateinr, vorname
Input #dateinr, plz
Input #dateinr, wohnort
End With
End Sub
Dim As Integer x
ReDim As tDatensatz datenarray(1)
'datenarray anlegen
ReDim datenarray(30)
For x = 1 To UBound(datenarray)
With datenarray(x)
.mitgliedsnummer = x
.name = "Meier" + Str(x)
.wohnort = "Berlin"
End With
Next
'datenarray im CSV-format in datei schreiben
Open ExePath + "\datei.dat" For Output As #1
For x = 1 To UBound(datenarray)
datenarray(x).speichern(1)
Next
Close 1
ReDim datenarray(1) 'datenarray zurücksetzen
'CSVdatei einlesen und in array schreiben
Open ExePath + "\datei.dat" For Input As #1
x = 1
Do
ReDim Preserve datenarray(x) 'neues arrayelement anlegen
datenarray(x).lesen(1) 'datensatz in arrayelement schreiben
x += 1 'nächstes element
Loop Until Eof(1)
Close 1
'ausdrucken
Print "Anzahl der Datensätze: "; UBound(datenarray)
Print
For x = 1 To UBound(datenarray)
Print "Datensatz Nr."; x
With datenarray(x)
Print "Mitgliedsnummer: "; .mitgliedsnummer
Print " Name: "; .name
Print
Sleep
End With
Next |
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 01.05.2022, 08:37 Titel: |
|
|
Vielen Dank für diesen Code, solche Beispiele geben mir sehr viel!
Was das Auslesen von Daten aus CSV-Dateien betrifft hatte ich eine sehr gut brauchbare Version von nemored. Dann habe ich aber CSV-Dateien bei den Übernahmedateien aus dem Vorsystem gefunden die als Trenn zeichen nur ein einfaches Komma und nicht "," hatten. Jetzt nutzte mir die vorhanden Funktion nichts mehr und ich schrieb eine eigene. Dabei machte ich mir aber die Grundidee von nemored zu eigen indem ich eine Schleife über den benötigten Teil csv-Datensatzes legte und nur die Indizes verwende die ich brauche. In meiner Funktion verwende ich immer nur den linken Teil des Satzes und kürze den Satz für die weitere Verarbeitung um diesen Teil. Sobald ich das hatte erkannte ich, dass ich mit nur 2 Erweiterungen beide Arten von csd-Dateien so zerlegen konnte - ohne beim Aufruf unterscheiden zu müssen. So sieht der Code aus:
Code: |
DECLARE FUNCTION csv_zerlegen (satz AS STRING) AS STRING
' csv-Datei zerlegen
'
Dim SHARED As STRING sWert
DIM SHARED AS INTEGER iKomma, iTyp
FUNCTION csv_zerlegen (sSatz AS STRING) AS STRING
IF LEFT(sSatz,1) = CHR(34) THEN
iTyp = 2
sSatz = RIGHT(sSatz, LEN(sSatz)-1) '1. Hochkomma entfernen
ELSE
iTyp = 1
endif
iKomma = INSTR(sSatz, ",")
sWert = LEFT(sSatz, iKomma - iTyp)
sSatz = RIGHT(sSatz, LEN(sSatz)-iKomma)
RETURN sWert
END FUNCTION
line input #fc, sSatz
FOR I = 1 TO 7
sWert = csv_zerlegen(sSatz)
IF I = 1 THEN iRey1 = VAL(sWert) ' Vereinssnummer
IF I = 2 THEN
IF sWert = "FALSE" THEN
bRey4 = 0 ' Flag: Verein=0
ELSE
bRey4 = 1 ' Flag: In Gründung=1
ENDIF
endif
IF I = 3 THEN sRey2 = sWert ' Vereinsname
IF I = 5 THEN iRey3 = VAL(sWert) ' Nummer
IF I = 6 THEN
IF VAL(sWert) > 0 THEN
bRey5 = 0 ' Flag: aktive=0
ELSE
bRey5 = 1 ' Flag: inaktiv = 1
ENDIF
ENDIF
NEXT
|
Im Grunde muss ich je CSV-Datei nur die FOR-Schleife anpassen, um alle erforderlichen Felder zu erhalten und dann ich Programm mit den IF-Statements die Felder selektiv einlesen.
EDIT: hab da noch einen Fehler gefunden! Die Funktion funktioniert gut wenn es in den CSV-Dateien keine Ausnahmen (z.B. Komma im Text) gibt. Bin dabei das einzubauen. _________________ Grüße
kilix |
|
Nach oben |
|
 |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1153 Wohnort: Ruhrpott
|
Verfasst am: 02.05.2022, 10:25 Titel: |
|
|
kilix hat Folgendes geschrieben: | ...als Trenn zeichen nur ein einfaches Komma und nicht "," hatten...
...wenn es in den CSV-Dateien keine Ausnahmen (z.B. Komma im Text) gibt... |
Ich glaube, da machst du einen kleinen Denkfehler. Die Anführungsstriche gehören nicht zum Trennzeichen, sondern zum Text, eben damit Kommata im Text nicht als Trennzeichen interpretiert werden. Kommt im Text kein Komma vor, sind die Anführungsstriche überflüssig, sie schaden aber auch nicht.
Ersetze in meinem letzten Beispielprogramm die Zeile Code: | .name = "Meier" + Str(x) | durch Code: | .name = """Meier, Sepp" + Str(x) + """" | dann siehst du, was ich meine (und daß auch die INPUT - Funktion von FB korrekt damit umgehen kann, es gibt von daher also eigentlich keinen Grund, einen eigenen Stringparser zu schreiben).
Gruß
grindstone. _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
 |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1153 Wohnort: Ruhrpott
|
Verfasst am: 02.05.2022, 12:50 Titel: |
|
|
Ich habe deinen letzten Code eimal -nun ja- überarbeitet
So würde ich diese Aufgabe lösen: Code: | ' csv-Datei zerlegen
'
Function csv_zerlegen (sSatz As String = "") As String
Static As String text 'sSatz merken als arbeitskopie
Static As ULong a, e 'pointer auf text, anfang und ende
Dim As String rueck
If Len(sSatz) Then 'neuer string, alles auf anfang setzen, ansonsten alten string weiter durchsuchen
text = sSatz 'satz merken als arbeitskopie
a = 1
e = 1
EndIf
If e = 0 Then 'satz ist abgearbeitet, leerstring zurückgeben
Return ""
EndIf
e = InStr(a, text, Any """,") 'anführungsstriche oder komma suchen
If Mid(text, e, 1) = """" Then 'text in anführungsstrichen
e = InStr(e + 1, text, """") 'endpointer auf 2. anführungsstriche setzen
e = InStr(e + 1, text, ",") 'endpointer auf nächstes komma setzen
EndIf
rueck = Trim(Mid(text, a, e - a), """") 'text zwischen den pointern zurückgeben und anführungsstriche entfernen
a = e + 1 'anfangspointer hinter endpointer setzen für nächsten wert
Return rueck
End Function
Dim As ULong fc, I, iRey1, iRey3
Dim As String sSatz, sRey2
Dim As boolean bRey4, bRey5
Line Input #fc, sSatz
iRey1 = Val(csv_zerlegen(sSatz)) ' Vereinssnummer
bRey4 = IIf(csv_zerlegen() = "FALSE", 0, 1) ' Flag: Verein=0 / In Gründung=1
sRey2 = csv_zerlegen() ' Vereinsname
csv_zerlegen() 'wert überspringen
iRey3 = Val(csv_zerlegen()) ' Nummer
bRey5 = IIf(Val(csv_zerlegen()) > 0, 0, 1) ' Flag: aktive=0 / inaktiv = 1
csv_zerlegen() 'wert überspringen
|
Der Stringparser funktioniert folgendermaßen: Wenn du einen Text als Parameter mitgibst, wird dieser gespeichert und der erste Wert zurückgegeben. Bei jedem weiteren Aufruf mit einem Leerstring oder ohne Parameter gibt er den nächsten Wert zurück. Ist der gesamte String abgearbeitet, wird ein Leerstring zurückgegeben.
Beachte besonders die statischen Variablen innerhalb der Funktion (STATIC), daduch sparst du dir die globalen Variablen außerhalb (SHARED).
Ich habe den Parser mit allen Gemeinheiten getestet, die mir gerade eingefallen sind, er scheint zu funktionieren. Falls jemand doch noch einen Fehler entdeckt, bitte melden.
Gruß
grindstone
EDIT:
Einen Fehler habe ich noch entdeckt (und korrigiert). _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen!
Zuletzt bearbeitet von grindstone am 03.05.2022, 10:20, insgesamt 2-mal bearbeitet |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4531 Wohnort: ~/
|
Verfasst am: 02.05.2022, 18:43 Titel: |
|
|
Schöner Einsatz von STATIC. Vielleicht denke ich daran, etwas in der Art ins Einsteigerhandbuch einzubauen.  _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 03.05.2022, 10:23 Titel: |
|
|
ich danke euch wieder für die vielen Codes die ihr mir sendet! Leider brauche ich länger, um das alles zu verarbeiten aber ich gebe vorerst alles in mein Archiv in dem ich nach Bedarf stöbern kann.
Was das von mir so genannte Trennzeichen "," betrifft ist mir schon klar, dass das eigentliche Trennzeichen das Komma ist und die Hochkomma die Felder begrenzen.
Was bei mir aber zu einem Problem geführt hat hat nichts mit Programmierung zu tun. Ich habe einige CSV-Dateien zerlegt und alle hatte die Hochkomma und das Komma. Doch dann stolperte ich über eine CSV-Datei bei der die Hochkomma fehlten. Das veranlasste mich die letzte Funktion 'csv-zerlegen' zu schreiben (die inzwischen für beide Varianten funktioniert). Allerdings habe ich gestern in der Zip-Datei die die aus dem Vorsystem stammenden CSV-Dateien enthält gesehen, dass alle die Kombination "," haben auch die die bei mir nur Kommas hatte. Dazu habe ich nur eine Erklärung: wahrscheinlich (erinnern kann ich mich nicht ) habe ich diese CSV-Datei als Tabelle eingelesen (nicht als Excel sondern im Format von OpenOffice) und dann wieder als CSV ausgegeben und OpenOffice speichert die " nicht mit. Also war meine Bemühung beide Varianten abzudecken vergebens.
Das hat mich doch viel Zeit gekostet. Das nun auf "," zu ändern ist kein Problem. Der Vorteil der neuen Funktion ist aber, dass innerhalb eines Textfeldes beliebig viele Beistriche sein können weil ich diese Prüfung in eine Schleife gelegt habe. Also werde ich jetzt alles bestehende auf diesen Standard bringen und mich erst dann Neuem zuwenden. _________________ Grüße
kilix |
|
Nach oben |
|
 |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1153 Wohnort: Ruhrpott
|
Verfasst am: 03.05.2022, 11:31 Titel: |
|
|
@kilix:
Natürlich ist das alles neu und braucht seine Zeit. Insbesondere der Umgang mit UDTs (TYPE) erfordert eine andere Denkweise. Ich empfehle dir aber dringend, dich damit zu befassen, denn es kann dir viel Arbeit beim Programmieren ersparen und steigert die Übersichtlichkeit von Programmen ganz enorm.
Was deine CSV - Dateien betrifft, hat das Vorhandensein der Anführungsstriche wahrscheinlich einen viel profaneren Grund: Da sie -wie ich schon geschrieben habe- auch nicht schaden, wenn kein Komma im Text vorkommt, werden sie einfach standardmäßig dazugeschrieben, damit spart man sich die Fallunterscheidung. Und wenn garantiert niemals ein Komma im Text vorkommt, kann man sie auch generell weglassen.
@nemored:
Diese Art von Parser benutze ich üblicherweise, um bestimmte Textstellen in HTML - Texten zu finden und zu isolieren.
Die Methode ist sehr flexibel, da sich die Textpointer in beide Richtungen schieben lassen, beispielsweise im gesamten Text ein bestimmtes Schlüsselwort suchen, dann von dort aus den Anfangspointer rückwärts zum Starttag und den Endpointer vorwärts zum Endtag. Und da der Text dabei nicht verändert wird, kann man das Ganze auch mehrmals durchführen.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4531 Wohnort: ~/
|
Verfasst am: 03.05.2022, 18:09 Titel: |
|
|
Wenn ich mich nicht sehr täusche, schreibt auch der FreeBASIC-Befehl WRITE einen String immer mit Anführungszeichen, egal ob nötig oder nicht. Eben genau aus dem Grund, dass dann nicht erst die Notwendigkeit geprüft wird. Wenn du also z. B. alle Einträge mit INPUT einliest und mit WRITE in eine neue Datei schreibst, sollten danach in der neuen Datei alle Einträge in Anführungszeichen stehen.
(PRINT schreibt dagegen immer ohne Anführungszeichen - solange man sie nicht selbst dazusetzt - und ist für Strings, die ein Komma enthalten, zu CSV-Zwecken nicht geeignet.)
((Und wenn ich jetzt so recht darüber nachdenke, beschleicht mich das Gefüh, dass das vor Kurzem schon geschrieben wurde - wenn dem so ist, tut es mir leid.)) _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
kilix
Anmeldungsdatum: 05.02.2022 Beiträge: 175
|
Verfasst am: 06.05.2022, 20:09 Titel: |
|
|
ich habe jetzt ein paar Tage nichts gemacht bin aber jetzt - wenn auch schaumgebremst wieder dran.
Die CSV-Dateien sind geklärt, es gibt in den Dateien die ich aus dem Vorsystem übernehme nur solche die " als Textbegrenzer und Komma als Feldbegrenzer haben. Damit ist alles einheitlich und kein Problem mehr in der Bearbeitung. Das funktioniert jetzt gut und problemlos.
Jetzt habe ich meinen Bubble-Sort auf den Quicksort von nemored umgestellt. Das schien ganz einfach aber ich mache da was falsch denn nach dem Sort ist der sortierte Array leer.
Ich habe hier symbolisch im Code dargestellt wie ich es codiert habe
Code: |
DECLARE sub quicksort(a() as string, byval s as integer = 0, byval e as integer = -1)
'
REDIM A(1 TO 1000) AS string
'
' Aufbau Sorttabelle
'
While Not Eof(fc)
IF iSatznr > 1000 THEN REDIM preserve A(1 TO iSatznr) ENDIF
A(iSatznr) = RIGHT("00000" & STR(iWer1),5) & RIGHT("00" & STR(iWer2b),2)
WEND
'
quicksort(A(), 0, -1)
'
FOR I = 1 TO UBOUND(A)
PRINT A(I): getkey '<=== A(I) ist leer
sWer1 = left(A(I),5)
usw
'
' Quicksort
'
sub quicksort(a() as string, byval s as integer = 0, byval e as integer = -1)
if s = 0 then s = lbound(a)
if e = -1 then e = ubound(a)
usw
|
Alles was ich sonst codiert habe und das mit dem Problem garantiert nichts zu tun hat habe ich weggelassen. Ich nehme an, dass der Fehler im Aufruf des Quicksort liegt denn bis dahin ist alles in Ordnung. Erst nach dem Quicksort ist die Tabelle leer.
EDIT 8.5.22:
Problem gelöst! offen gesagt weiß nicht exakt wodurch, habe zurück geändert auf den Bubble-Sort, drei sachliche Verarbeitungsfehler korrigiert und nachdem das funktioniert hat wieder zum Quicksort gewechselt. _________________ Grüße
kilix
Zuletzt bearbeitet von kilix am 08.05.2022, 08:30, insgesamt einmal bearbeitet |
|
Nach oben |
|
 |
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|