Push-Nachrichten von MacTechNews.de
Würden Sie gerne aktuelle Nachrichten aus der Apple-Welt direkt über Push-Nachrichten erhalten?
Forum>Software>Fortran: Variableneinlesung aus einer csv-Datei

Fortran: Variableneinlesung aus einer csv-Datei

virk
virk01.05.2311:19
Wie kann ich FORTAN beibringen, daß Variablen (character) aus einer csv-Datei nur bis zum Semikolon gelesen werden sollen?

Beispiel:

bedarf_0001.txt;====== Definition 1 ======;====== ;Definition 1; ======
bedarf_0002.txt;====== ef ======;====== ;ef; ======
bedarf_0003.txt;====== Definition 3 ======;====== ;Definition 3; ======
bedarf_04.txt;====== Def 4 ======;====== ;Definition 4; ======
bedarf_0005.txt;====== Test ======;====== ;Test; ======
bedarf_0006.txt;====== Definition 6 ======;====== ;Definition 6; ======
bedarf_0007.txt;====== Definition 7 ======;====== ;Definition 7; ======
bedarf_0008.txt;====== Definition 8 ======;====== ;Definition 8; ======
bedarf_0009.txt;====== Definition 9 ======;====== ;Definition 9; ======
Es möge aus der vierten Zeile "bedarf_04.txt" und dann "====== Def 4 ======" gelesen werden; Rest ist zu ignorieren und es ist zur nächsten Zeile überzugehen.

Code bislang ist folgender, der aber nur funktioniert, wenn character-Länge angepasst wird und die Einträge in der csv-Datei immer gleichlang sind:
program doku
character dn*16, di*26
open (3,file = 'datei.csv', status = 'old')
100 read (3,'(a15,1x,a)',end=1000) dn,di
open (4,file = dn,status='replace')
write (4,*) di
close(4)
goto 100
1000 end
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0

Kommentare

Wellenbrett01.05.2311:34
Krass, ein Fortran-Problem im Jahr 2023. Leider habe ich keine Ahnung von Fortran, Aber ich habe mal zwei Computer-Epochen miteinander verknüpft und ChatGPT zu Deinem Problem befragt und zwar mit dem ersten Satz Deines Fragetextes (ohne die nachfolgenden Beispiele von Dir). Die Antwort von ChatGPT lautet:
ChatGPT
Fortran ist eine Programmiersprache, die in der Lage ist, Daten aus verschiedenen Quellen zu lesen, einschließlich CSV-Dateien. Um eine CSV-Datei in Fortran zu lesen und zu speichern, müssen Sie zuerst eine geeignete Formatierung definieren. Das bedeutet, dass Sie die Positionen und die Länge der einzelnen Felder in der CSV-Datei angeben müssen.

Um nur den Text bis zum Semikolon zu lesen, müssen Sie in Fortran eine passende Länge für Ihre character-Variablen definieren. Wenn der Text in der CSV-Datei variabler Länge hat, müssen Sie möglicherweise eine spezielle Methode verwenden, um die Texte bis zum Semikolon zu extrahieren.

Ein Beispielprogramm, das eine CSV-Datei mit Textfeldern bis zum Semikolon liest und die Daten in einer Fortran-Variablen speichert, könnte folgendermaßen aussehen:
program read_csv
  implicit none

  integer :: i, j, n
  character(100) :: line
  character(50) :: field1
  character(50) :: field2
  character(50) :: field3
  character(50) :: field4
  character(50) :: field5

  open(10, file='data.csv', status='old')

  n = 0
  do
    read(10, '(a)', iostat=n) line
    if (n < 0) exit
    read(line, '(a50,1x,a50,1x,a50,1x,a50,1x,a50)', iostat=n) field1, field2, field3, field4, field5
    ! do something with the data
  end do

  close(10)
end program read_csv

Hier wird eine CSV-Datei mit fünf Feldern (field1 bis field5) gelesen, wobei jedes Feld eine Länge von 50 Zeichen hat. Der read-Befehl liest die gesamte Zeile in die Variable line, und die read-Anweisung danach extrahiert die Textfelder durch Angabe der Länge der einzelnen Felder und dem Semikolon-Trennzeichen.

Wenn Ihre CSV-Datei eine andere Feldanzahl oder Längen hat, müssen Sie die entsprechenden Anpassungen an dem Format vornehmen.
Das ist hilfreich, oder? Ich finde das so abgefahren... ChatGPT muss also mit Fortran-Code trainiert worden sein
+2
Wellenbrett01.05.2311:48
Jetzt habe ich ChatGPT noch mehr Kontext gegeben und konkret nach dem Problem in Deinem Code suchen lassen. Hier wieder die Antwort von ChatGPT:
ChatGPT
Das Programm, das Sie erstellt haben, liest die CSV-Datei in einer Schleife und extrahiert die beiden Textfelder (dn und di) aus jeder Zeile. Das Problem hierbei ist, dass Sie keine Methode implementiert haben, um die Textfelder bis zum Semikolon zu extrahieren. Sie müssen daher die Textfelder manuell aus jeder Zeile extrahieren, indem Sie die Positionen der Semikolons suchen und den Text entsprechend aufteilen.

Ein Beispielprogramm, das die CSV-Datei liest und die Textfelder bis zum Semikolon extrahiert, könnte folgendermaßen aussehen:
program doku
  implicit none

  character(100) :: line
  character(16) :: dn
  character(26) :: di
  integer :: i, j, n

  open(3, file='datei.csv', status='old')

  do
    read(3, '(a)', iostat=n) line
    if (n < 0) exit
    i = index(line, ';')
    dn = line(1:i-1)
    j = index(line(i+1:), ';')
    di = trim(line(i+1:i+j-1))
    ! do something with the data
    write(*,*) dn, di
  end do

  close(3)
end program doku
Hier wird die CSV-Datei Zeile für Zeile gelesen, und der index-Befehl wird verwendet, um die Positionen der Semikolons zu finden. Dann werden die Textfelder durch Extrahieren der Substrings zwischen den Semikolons definiert.

Dieses Programm sollte auch für CSV-Dateien mit unterschiedlichen Feldlängen funktionieren, solange die Semikolons als Trennzeichen verwendet werden.
+2
Wellenbrett01.05.2311:54
Obwohl ich ChatGPT schon etwas kenne und mehrmals mit menschlicher Sprache getestet hatte, bin ich jetzt doch von dieser fundierten Antwort im Kontext ziemlich sprachlos.
+2
marm01.05.2312:00
Wellenbrett
Das ist hilfreich, oder? Ich finde das so abgefahren... ChatGPT muss also mit Fortran-Code trainiert worden sein
Ich habe die Frage von virk zuvor auch in ChatGPT kopiert und eine ganz andere Antwort erhalten. In letzter Zeit habe ich einige Skripte (in Python, Ruby und AppleScript) mit Hilfe von ChatGPT erstellt. Die ersten Antworten enthalten oft Fehler und eignen sich daher nicht zum Einsatz ohne Testen und Verbessern. Beharrliches Nachfragen, das Mitteilen von Fehlermeldungen und Präzisieren helfen dabei, eine Lösung zu erhalten, die ich ohne ChatGPT nicht gefunden hätte.
+2
Wellenbrett01.05.2312:07
marm
Wellenbrett
Das ist hilfreich, oder? Ich finde das so abgefahren... ChatGPT muss also mit Fortran-Code trainiert worden sein
Ich habe die Frage von virk zuvor auch in ChatGPT kopiert und eine ganz andere Antwort erhalten. In letzter Zeit habe ich einige Skripte (in Python, Ruby und AppleScript) mit Hilfe von ChatGPT erstellt. Die ersten Antworten enthalten oft Fehler und eignen sich daher nicht zum Einsatz ohne Testen und Verbessern. Beharrliches Nachfragen, das Mitteilen von Fehlermeldungen und Präzisieren helfen dabei, eine Lösung zu erhalten, die ich ohne ChatGPT nicht gefunden hätte.
Ja, den Code ungeprüft zu verwenden, wäre fahrlässig, je nachdem wie wichtig die Anwendung ist. Du hast ja einen guten Umgang für Dich gefunden, um ChatGPT sinnvoll einzusetzen.

Das und vieles mehr steht der Menschheit noch bevor.

Hat ChatGPT tatsächlich auch Ahnung von AppleScript? Hast Du da eine andere (schlechtere) Qualität der Lösungen als bei den beiden verbreiteten Sprachen bemerkt?
0
Wellenbrett01.05.2312:18
Ich vermute, zu Fortran gibt es sehr viel Code in irgendwelchen Archiven und in der Literatur, bei Python und Ruby sowieso. Aber bei AppleScript stehen sicherlich nicht so umfangreiches Trainingsmaterial zur Verfügung. Insofern würde es mich wundern, wenn die Qualität der Antworten von ChatGPT bei AppleScript da auf dem gleichen Niveau der stark verbreiteten Sprachen ist.
0
Wellenbrett01.05.2312:18
virk, was sagst Du zu der Lösung von ChatGPT?
0
virk
virk01.05.2312:29
Komme gerade im Büro an; muß erst mal verschnaufen. Dann sehe ich mir das näher an. Ich melde mich auf jeden Fall. Danke Euch soweit.
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0
marm01.05.2312:39
Wellenbrett
Hat ChatGPT tatsächlich auch Ahnung von AppleScript? Hast Du da eine andere (schlechtere) Qualität der Lösungen als bei den beiden verbreiteten Sprachen bemerkt?
Es ist eher so, dass ich ChatGPT Lösungen in mehreren Sprachen vorschlagen lasse. Meine Skripte sind auch eher kurz zum Einbinden in einen Kurzbefehl.
Mal funktioniert das Ergebnis in der einen Sprache überhaupt nicht, ChatGPT landet in einer Sackgasse und fängt an, falsche Lösungen zu wiederholen. In einer anderen Sprache klappt es dann.
Bei AppleScript fällt auf, dass oft die Syntax vermurkst ist und ich Fehlermeldungen erhalte, wie zum Beispiel dass ein Zeilenende erwartet worden sei.
+1
virk
virk01.05.2313:23
@Wellenbrett: Der Beitrag von 11:34 ignoriert genau mein Problem. Dann habe ich das Progrämmchen von 11:48 Uhr genommen; mir ohne es näher anzugucken in den Editor geladen, meine Ausgabezeilen dazugestrickt und compiliert. Es macht anscheinend genau das, was es soll.
Extrem cool! Recht Herzlichen Dank an Euch, die Ihr Euch bemüht habt. Ich weiß, Ihr hättet eigentlich schon anfangen wollen, zu saufen
Jetzt/gleich sehe mich mir den code mal näher an
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
+3
Wellenbrett01.05.2314:19
virk
@Wellenbrett: Der Beitrag von 11:34 ignoriert genau mein Problem.
...
Na ja, ChatGPT hat sich auch da schon Deinem spezifischen Problem zumindest angenähert, eiert aber noch ein bißchen herum: "Um nur den Text bis zum Semikolon zu lesen, müssen Sie in Fortran eine passende Länge für Ihre character-Variablen definieren. Wenn der Text in der CSV-Datei variabler Länge hat, müssen Sie möglicherweise eine spezielle Methode verwenden, um die Texte bis zum Semikolon zu extrahieren."
virk
Dann habe ich das Progrämmchen von 11:48 Uhr genommen; mir ohne es näher anzugucken in den Editor geladen, meine Ausgabezeilen dazugestrickt und compiliert. Es macht anscheinend genau das, was es soll. ...
Ja, da hatte ich ChatGPT mehr Kontext aus Deiner Eingangsfrage geliefert. Absolut erstaunlich finde ich beispielsweise wie ChatGPT die von Dir in Deinem Code verwendeten Variablen di und dn aufgreift und in "seiner" - offensichtlich funktionierenden - Lösung verwendet.
Toll, daß Du eine Lösung hast
0
Wellenbrett01.05.2314:35
marm
...
Mal funktioniert das Ergebnis in der einen Sprache überhaupt nicht, ChatGPT landet in einer Sackgasse und fängt an, falsche Lösungen zu wiederholen. In einer anderen Sprache klappt es dann.
...
Danke für Deine Rückmeldung. ChatGPT berücksichtigt in der kostenlosen Variante nur eine begrenzte zurückliegende Textmenge als Kontext. Was in Deiner Anfrage also mehr als 1000 oder 10000 Zeichen (weiß gerade nicht, was von beiden) zurückliegt ist also "aus den Augen aus dem Sinn". Vielleicht läßt sich das für bessere Lösungen berücksichtigen.
marm
Bei AppleScript fällt auf, dass oft die Syntax vermurkst ist und ich Fehlermeldungen erhalte, wie zum Beispiel dass ein Zeilenende erwartet worden sei.
ChatGPT scheint also bei AppleScript mehr Syntax-Fehler zu machen, als bei anderen (mehr verbreiteten) Sprachen. Syntaxfehler wirken eigentlich ziemlich banal im Vergleich zu dem was ChatGPT dabei jeweils richtig macht. Ich frage mich, ob das mit der geringeren Menge an Trainingsmaterial bei AppleScript zu tun hat, oder ob es an etwas anderem liegt.
0
Wellenbrett01.05.2314:43
marm
...
Ich habe die Frage von virk zuvor auch in ChatGPT kopiert und eine ganz andere Antwort erhalten.
Hattest Du dabei virks ursprüngliche Frage komplett im ChatGPT-Prompt kopiert? Ich hatte ja zwei Prompts nacheinander verwendet. Ich frage mich, ob ChatGPT auch unterschiedliche Lösungen präsentiert hätte, wenn wir identische Anfragen gestellt hätten.
0
gfhfkgfhfk01.05.2315:28
Wellenbrett
Krass, ein Fortran-Problem im Jahr 2023. Leider habe ich keine Ahnung von Fortran, Aber ich habe mal zwei Computer-Epochen miteinander verknüpft und ChatGPT zu Deinem Problem befragt und zwar mit dem ersten Satz Deines Fragetextes (ohne die nachfolgenden Beispiele von Dir). Die Antwort von ChatGPT lautet:
Die beiden Antwort tuen weh, da ChatGPT das Problem zwar löst, aber so einige Probleme einbaut. Man sollte tunlichst keine absoluten Zahlen für die IO-Units mehr verwenden. Sonst kann das mit existierenden Definitionen kollidieren. Die Definitionen für die drei Standard Kanäle Ein-, Aus- und Fehlerausgabe sind bereits durch den Compiler als Konstanten definiert.

Dann könnte man sicherlich die Dateinamen noch per Kommandozeile übergeben.
program read_csv
    use iso_fortran_env
    implicit none

    character(len=*), parameter :: file_name = 'datei.csv'
    character(len=*), parameter :: format_read_line = '(A)'
    character(len=*), parameter :: format_write_line= '(A20, ";", A30)'
    character(len=*), parameter :: format_error_open= '("cannot open file: ", A)'

    character(len=256) :: error_msg, line, s1, s2
    integer :: file_handle, error

    open (NEWUNIT=file_handle, FILE=file_name, STATUS='old', ACTION='READ', IOMSG=error_msg, IOSTAT=error)

    if (0 /= error) then
        write (UNIT=error_unit, FMT=format_error_open) error_msg
        stop
    end if

    do
        read (UNIT=file_handle, FMT=format_read_line, IOSTAT=error) line
        if (0 /= error) exit

        call split_string(line, s1, s2)
        write (output_unit, FMT=format_write_line) s1, s2
    end do

    close(file_handle)
end program

subroutine split_string (s1, s2, s3)
    character(len=*), intent(in) :: s1
    character(len=256), intent(out) :: s2, s3

    character, parameter :: trenner = ';'
    character(len=256) :: substr
    integer :: i

    i = index(s1, trenner)
    s2 = trim(s1(:i-1))

    substr = s1(i+1:)
    i = index(substr, trenner)
    s3 = trim(substr(:i-1))
end subroutine split_string
0
marm01.05.2315:34
Wellenbrett
Hattest Du dabei virks ursprüngliche Frage komplett im ChatGPT-Prompt kopiert? Ich hatte ja zwei Prompts nacheinander verwendet. Ich frage mich, ob ChatGPT auch unterschiedliche Lösungen präsentiert hätte, wenn wir identische Anfragen gestellt hätten.
Ja, komplett kopiert und 1:1 eingefügt. ChatGPT erstellt unterschiedliche Antworten, wie sich leicht nachprüfen lässt, indem man mit der gleichen Frage zwei Chats startet. Selbst simple Fragen wie "löse die Aufgabe 2 + x = 4" liefert unterschiedliche Antworten.
hier übrigens die Antwort. Sie ist recht nah am Ausgangscode:
program doku
  character dn*16, di*26
  integer :: semicolon_index
  open (3,file = 'datei.csv', status = 'old')
  100 read (3,'(a15,1x,a)',end=1000) dn,di
  semicolon_index = INDEX(di, ";") - 1  ! -1 to exclude the semicolon
  open (4,file = dn, status='replace')
  write (4,*) di(1:semicolon_index)
  close(4)
  goto 100
1000 end
Ich frage mich, ob das mit der geringeren Menge an Trainingsmaterial bei AppleScript zu tun hat, oder ob es an etwas anderem liegt.
Eine Ursache für einen Syntaxfehler war zum Beispiel, dass ChatGPT für das AppleScript einen Variablennamen wählte, der wohl eine definierte Bedeutung hat. Ich könnte mir vorstellen, dass die geringere Formelhaftigkeit von AppleScript ein Problem ist.
0
virk
virk01.05.2316:14
@gfhfkgfhfk: Version läuft mit drei zusätzlichen Zeilen für meine Ausgabe (für jede Zeile eine neue Datei erzeugen) auch, konterkariert aufgrund meiner "Dorf-Syntax" Deine Bemühungen
Danke! Jedoch vermag ich den Unterschied nicht zu beurteilen. Auch habe ich den code nach 72 Zeichen in eine neue Zeile verschieben müssen. Nutze gfortran 12.1.0 und weiß nicht, ob/wie ich dem compiler begreiflich machen kann, daß er über 72 Zeichen hinaus liest.
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0
virk
virk01.05.2316:23
Die Version, die marm 15:34 eingestellt hat, ist bislang die mir am passendsten: Nicht nur wird wunschgemäß gelesen, es wird auch wunschgemäß di geschrieben, da ich nämlich den Schreibbefehl noch auf

write (4,*) '===== ',di(1:semicolon_index),' ====='

erweitere. So wird die Variable di nicht immer bis auf ihre Charakterlänge aufgefüllt, sondern Leerzeichen und Gleichheitszeichen erscheinen direkt nach "di". Na, hoffentlich habe ich mich verständlich ausgedrückt. Danke allen soweit!
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0
virk
virk01.05.2316:38
Nachtrag: Auch die 15:34 Uhr-Version hat u.U. Nachteile, aber der Lösungsansatz ist verstanden.
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0
gfhfkgfhfk01.05.2319:24
virk
Danke! Jedoch vermag ich den Unterschied nicht zu beurteilen. Auch habe ich den code nach 72 Zeichen in eine neue Zeile verschieben müssen. Nutze gfortran 12.1.0 und weiß nicht, ob/wie ich dem compiler begreiflich machen kann, daß er über 72 Zeichen hinaus liest.
Da hast Du schlicht die falsche Dateiendung genutzt. Wenn man .f nutzt wird automatisch der Modus für den fixed form Source Code aktiviert, der ist veraltet. Lochkarten lassen schön grüßen. Wenn man .f90, .f95, .f03, .f08 nutzt, dann wird automatisch die free form genutzt. Bei Fortran 2003 kann man dann 136 Zeichen in eine Zeile schreiben. Der ganze Code ist so geschrieben, dass er Fortran 2003 voraussetzt, was beim GCC 12.1.0 definitiv erfüllt ist. Zwischen diesen beiden Modi kann man aber auch mit einem Compilerargument umschalten. Dann kann man mit -std=f2003 explizit die entsprechende Fortran Version aktivieren.

Wenn man die Dateiendungen groß schreibt, d.h. .F, .F90 usw. dann wird automatisch der Präprozessor und aktiviert, und der führt dann Textersetzungen durch.
0
almdudi
almdudi01.05.2319:35
virk
Wie kann ich FORTAN beibringen, daß Variablen (character) aus einer csv-Datei nur bis zum Semikolon gelesen werden sollen?
[…]

Es möge aus der vierten Zeile "bedarf_04.txt" und dann "====== Def 4 ======" gelesen werden; Rest ist zu ignorieren und es ist zur nächsten Zeile überzugehen.
Das widerspricht sich aber - du willst bis zum zweiten Semikolon einlesen.
0
virk
virk01.05.2319:51
almdudi
Das widerspricht sich aber - du willst bis zum zweiten Semikolon einlesen.
Ja, vielleicht hast Du recht, und ich habe mich nicht korrekt ausgedrückt: Ich will bis zum zweiten Semikolon lesen, das zweite Semikolon selbst interessiert mich jedoch nicht
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0
virk
virk01.05.2319:52
gfhfkgfhfk
virk
Danke! Jedoch vermag ich den Unterschied nicht zu beurteilen. Auch habe ich den code nach 72 Zeichen in eine neue Zeile verschieben müssen. Nutze gfortran 12.1.0 und weiß nicht, ob/wie ich dem compiler begreiflich machen kann, daß er über 72 Zeichen hinaus liest.
Da hast Du schlicht die falsche Dateiendung genutzt. Wenn man .f nutzt wird automatisch der Modus für den fixed form Source Code aktiviert, der ist veraltet. Lochkarten lassen schön grüßen. Wenn man .f90, .f95, .f03, .f08 nutzt, dann wird automatisch die free form genutzt. Bei Fortran 2003 kann man dann 136 Zeichen in eine Zeile schreiben. Der ganze Code ist so geschrieben, dass er Fortran 2003 voraussetzt, was beim GCC 12.1.0 definitiv erfüllt ist. Zwischen diesen beiden Modi kann man aber auch mit einem Compilerargument umschalten. Dann kann man mit -std=f2003 explizit die entsprechende Fortran Version aktivieren.

Wenn man die Dateiendungen groß schreibt, d.h. .F, .F90 usw. dann wird automatisch der Präprozessor und aktiviert, und der führt dann Textersetzungen durch.
Das probiere ich doch jetzt glatt mal aus das mit den Endungen Danke!
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0
marm01.05.2320:01
Frage: Liest dieses Fortran-Programm das erste oder zweite Semikolon und woran erkenne ich das?
Antwort: Das Fortran-Programm liest das zweite Semikolon. Dies kann man daran erkennen, dass das Programm die Funktion INDEX(di, ";") aufruft und das Ergebnis um 1 reduziert (semicolon_index = INDEX(di, ";") - 1), um das erste Semikolon auszuschließen. Dadurch wird nur der Teilstring von di geschrieben, der vor dem zweiten Semikolon steht (write (4,*) di(1:semicolon_index)).

Frage: Ist das erste oder zweite Programm besser und machen sie das gleiche?
Antwort: Beide Programme erfüllen dieselbe grundlegende Aufgabe, nämlich das Lesen einer CSV-Datei und die Ausgabe der Werte in zwei Spalten, die durch ein Semikolon getrennt sind.
...
Das zweite Programm verwendet eine modernere Schleifenkonstruktion und eine separate Subroutine ("split_string"), um jede Zeile in zwei Teile zu teilen. Es verwendet auch aussagekräftigere Variablennamen und moderne Fortran-Syntax. Es gibt auch eine Fehlerbehandlung beim Öffnen der Datei und das Programm stoppt, falls es ein Problem gibt.
Insgesamt ist das zweite Programm aufgrund seiner moderneren Syntax, besseren Lesbarkeit und besseren Fehlerbehandlung eine bessere Wahl.
+2
gfhfkgfhfk03.05.2313:11
gfhfkgfhfk

program read_csv
    …
Ok, ich habe mir das nochmals angeschaut. Es geht auch etwas eleganter, und man kann auch ohne Verrenkungen nur die Anteile der Strings ausgeben, die relevant sind. Stringverarbeitung ist etwas was ich mit Fortran eigentlich nie mache.
! read_csv.f08
! compile with gfortran -std=f2008
program read_csv
    use iso_fortran_env
    implicit none

    character(len=*), parameter :: file_name = 'datei.csv'
    character(len=*), parameter :: format_read_line = '(A)'
    character(len=*), parameter :: format_write_line= '(A, ";", A)'
    character(len=*), parameter :: format_error_open= '("cannot open file: ", A)'

    character(len=256) :: error_msg, line, s1, s2
    integer :: file_handle, error

    open (NEWUNIT=file_handle, FILE=file_name, STATUS='old', ACTION='READ', IOMSG=error_msg, IOSTAT=error)

    if (0 /= error) then
        write (UNIT=error_unit, FMT=format_error_open) error_msg
        stop
    end if

    do
        read (UNIT=file_handle, FMT=format_read_line, IOSTAT=error) line
        if (0 /= error) exit

        call split_string(';', line, s1, s2)
        write (output_unit, FMT=format_write_line) s1(:len_trim(s1)), s2(:len_trim(s2))
    end do

    close(file_handle)
contains
    subroutine split_string (separator, s1, s2, s3)
        character, intent(in) :: separator
        character(len=*), intent(in) :: s1
        character(len=256), intent(out) :: s2, s3

        character(len=256) :: substr
        integer :: i

        i = index(s1, separator)
        s2 = trim(s1(:i-1))

        substr = s1(i+1:)
        i = index(substr, separator)
        s3 = trim(substr(:i-1))
    end subroutine split_string
end program
+1
virk
virk03.05.2313:38
Ich habe auch noch was gemacht:

      program doku
      character line*100
      open(3,file='datei.csv', status='old')
  100 read(3,'(a)',iostat=n) line
      if (n < 0) goto 1000
      i = index(line,';')
      j = index(line(i+1:),';')
      open (4,file = line(1:i-1)//'.txt',status='replace')
      write(4,*) '===== ',trim(line(i+1:i+j-1)),' ====='
      close(4)
      goto 100
 1000 end

Deines speichere ich mir auch weg. Danke!
Das Teil macht das, was ich haben will. Ich bin so ein kurz&knapp-Fanatiker.
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
0
Wellenbrett03.05.2314:17
marm
Frage: Liest dieses Fortran-Programm das erste oder zweite Semikolon und woran erkenne ich das?
Antwort: Das Fortran-Programm liest das zweite Semikolon. Dies kann man daran erkennen, dass das Programm die Funktion INDEX(di, ";") aufruft und das Ergebnis um 1 reduziert (semicolon_index = INDEX(di, ";") - 1), um das erste Semikolon auszuschließen. Dadurch wird nur der Teilstring von di geschrieben, der vor dem zweiten Semikolon steht (write (4,*) di(1:semicolon_index)).

Frage: Ist das erste oder zweite Programm besser und machen sie das gleiche?
Antwort: Beide Programme erfüllen dieselbe grundlegende Aufgabe, nämlich das Lesen einer CSV-Datei und die Ausgabe der Werte in zwei Spalten, die durch ein Semikolon getrennt sind.
...
Das zweite Programm verwendet eine modernere Schleifenkonstruktion und eine separate Subroutine ("split_string"), um jede Zeile in zwei Teile zu teilen. Es verwendet auch aussagekräftigere Variablennamen und moderne Fortran-Syntax. Es gibt auch eine Fehlerbehandlung beim Öffnen der Datei und das Programm stoppt, falls es ein Problem gibt.
Insgesamt ist das zweite Programm aufgrund seiner moderneren Syntax, besseren Lesbarkeit und besseren Fehlerbehandlung eine bessere Wahl.

Das ist sooooo abgefahren. Noch vor einem Jahr hätte ich nie gedacht, dass das in absehbarer Zeit möglich sein wird.

Marm, die Frage an ChatGPT, welches Programm besser ist, war echt trickreich.
+1
Wellenbrett03.05.2314:27
gfhfkgfhfk
gfhfkgfhfk

program read_csv
    …
Ok, ich habe mir das nochmals angeschaut. Es geht auch etwas eleganter, und man kann auch ohne Verrenkungen nur die Anteile der Strings ausgeben, die relevant sind. Stringverarbeitung ist etwas was ich mit Fortran eigentlich nie mache.
! read_csv.f08
! compile with gfortran -std=f2008
program read_csv
   ...
end program
gfhfkgfhfk:
Toller Service für virk
Für was wird Fortran aktuell denn noch verwendet? Hatte die NASA nicht vor einigen Jahren (also in diesem Jahrtausend) ältere Fortran-Veteranen aus den Ruhestand geholt, bzw. gebeten, sich nochmals mit Ihren alten Programme zu beschäftigen, damit die mit neueren Sprachen gekoppelt werden können? Und bei Amerikanischen Banken gab es ein ähnliches Vorgehen in Bezug auf Cobol, wenn ich mich recht erinnere.
0
virk
virk03.05.2315:11
Wellenbrett
Toller Service für virk
Zweifelsohne! Dabei liefere ich auch nur service für jemanden in einem anderen Forum. Da ich mich gerade mit FORTRAN mal wieder herumschlage, hatte ich mich dessen angenommen; habe auch dank Euch was gelernt.

Wir hier nutzen Fortran als ein Auslegungstool für unsere Anlagen (Ammoniakabsorptionskälteanlagen und -wärmepumpen). Es gibt alte Stoffdatenroutinen, die halt in Fortran verfaßt und noch immer gültig sind. Parallel haben wir auch eine Entwicklung unter python am laufen, jedoch lässt das noch auf sich warten.
„Gaststättenbetrieb sucht für Restaurant und Biergarten Servierer:innen und außen.“
+1
gfhfkgfhfk03.05.2317:00
Wellenbrett
Für was wird Fortran aktuell denn noch verwendet? Hatte die NASA nicht vor einigen Jahren (also in diesem Jahrtausend) ältere Fortran-Veteranen aus den Ruhestand geholt, bzw. gebeten, sich nochmals mit Ihren alten Programme zu beschäftigen, damit die mit neueren Sprachen gekoppelt werden können?
Man muss sich etwas mit der Geschichte von Fortran auseinandersetzen, um die Frage sinnvoll zu beantworten. Persönlich teile ich diese in drei Phasen ein.
  • Altes Fortran d.h. F77, F66 und die Prä-ANSI-Zeit mit ihrem Wildwuchs: Charakteristisch für diese Zeit ist der fixed-form Sourcecode (notwendig für die damals noch üblichen Lochkarten), COMMON Blöcke, solche Gemeinheiten wie computed goto, statische Allokation von Arbeitsspeicher, implizite Variablen Deklaration (deshalb bei mir das "implicit none") … insgesamt ein Alptraum für jeden der strukturiert programmieren will.
  • Die Fortran90 und Fortran95 Ära: Es gibt die ersten Versuche Fortran zu modernisieren. Es wird der free-form Sourcecode eingeführt. Es gibt Module. Man kann dynamisch Speicher für Variablen und Felder allozieren, etliches wird modernisiert. Aber es gibt ein ganz großes Manko, es gibt keinen freien modernen Compiler. GNU hat noch immer nur den g77 am Start, und der kann nur F77 und eine Version mit GNU-Erweiterungen. Letztere sind so populär, dass sie auch in kommerzielle Compiler Einzug halten.
  • Seit Fortran2003 ist Fortran wirklich in der Gegenwart angekommen: Es gibt nun eine genormte C Schnittstelle, so dass man ohne miesen Tricks C Funktionen aufrufen kann bzw. Fortran Routine von C aus aufrufen kann. Dann ist Fortran mittlerweile eine objektorientierte Programmiersprache. Man kann ganz nach C++ Vorbild RAII als Programmierstil pflegen, so dass der Compiler automatisch hinter einen aufräumt. Die vielen GNU Erweiterungen sind in leicht anderer Form Teil der ISO Norm geworden. Es gibt endlich genormte Datentypen z.B. real(kind=real32), real(kind=real64), real(kind=real128). Und was ganz wesentlich ist, es gibt mit gfortran und einigen anderen Compiler endlich frei verfügbare Compiler, so dass auch alle Interessierten Zugriff auf die neuste Technik haben.

Wenn man Software für HPC-Cluster schreiben will, gibt es wegen der Infrastruktur drei Sprachen, die man prinzipiell nehmen kann: C, C++ oder Fortran. Das liegt daran, dass die wichtigsten Techniken auf einem Cluster MPI und OpenMP sind. Nur für diese drei Sprachen gibt es direkte Unterstützung, für alle andere Sprachen braucht man spezielle Erweiterungen, um etwa MPI zu nutzen. Da MPI zur Interknotenkommunikation auch über Infiniband genutzt wird, führt daran kein Weg vorbei, sonst muss man wirklich bei den Basics von Infiniband anfangen. Dafür hat man keine Zeit. Dazu gibt es in den verbreiteten MPI-Implementationen spezielle Plugins, so dass der Job Scheduler direkt die korrekte Knotenkonfiguration an das aufstartende Programm übermitteln kann. Nutzt man kein MPI, darf man das alleine zusammenbauen und das Programm auf den verschiedenen Knoten in seinem Skript manuell starten. Es geht, es ist aber zusätzlicher Aufwand.

Warum ist Fortran für HPC-Software eine gute Wahl?
Fortran ist für einen Wissenschaftler weniger komplex als C und definitiv als C++. Man kann sich mehr auf die Wissenschaft konzentrieren, und mit OpenACC gibt es eine sehr elegante Lösung CUDA Code zu generieren, in dem man aus leicht modifizierten Fortran Code offloading auf die GPGPU macht. Persönlich halte ich modernes Fortran für eine elegante Programmiersprache, um wissenschaftliche Probleme in Programmen mit sehr hoher Ausführungsgeschwindigkeit umzusetzen. Das vielfach gehypte Python ist auch nicht viel besser, was den Programmierstil betrifft. Python mag mittlerweile Vorteile in der Zahl der Bibliotheken haben, aber Fortran Code ist sehr viel schneller. D.h. musst Du selbst für einen Cluster die Routinen schreiben, ist Python sofort raus. Außer Du fängst an Python Plugins in C zu schreiben, und das ist nichts, was ich einem Naturwissenschaftler oder Ingenieur empfehlen würde.

Persönlich mag ich Fortran2003 ff. sehr . Was F77 betrifft (Es fehlt hier im Forum definitiv das Kotz-Emoji), mehr gibt es dazu nicht zu schreiben.
0
Wellenbrett03.05.2317:54
gfhfkgfhfk
Danke für die ausführliche Antwort! Interessant, diese drei Phasen von Fortran so klar zu unterscheiden; auch dass es inzwischen objektorientiert ist, war mir vollkommen neu. Die Syntax im Code von ChatGPT oben wirkt auf mich irgendwie simpel, als gäbe es wenig abstrakte Konzepte in der Sprache, aber das kann natürlich täuschen.
0
bmonno204.05.2312:57
virk und alle anderen
Herzlichen Dank für die Beiträge hier. Vor knapp 50 Jahren war FORTRAN die erste Programmiersprache mit der ich im Mathe-Studium zu tun hatte, damals noch mit Lochkarten. War damals schon rattenschnell und man konnte nette Dinge damit realisieren.
Die Weiterentwicklung von FORTRAN habe ich erst hier kennen gelernt. Vielleicht nehme ich das Thema wieder auf, um die grauen Zellen ein wenig zu trainieren. Danke dafür.
0
gfhfkgfhfk04.05.2320:20
bmonno2
Die Weiterentwicklung von FORTRAN habe ich erst hier kennen gelernt. Vielleicht nehme ich das Thema wieder auf, um die grauen Zellen ein wenig zu trainieren. Danke dafür.
Falls es wirklich Interesse gibt. Es gibt zwei empfehlenswerte Bücher für aktuelles Fortran:
  • Fortran for Scientists and Engineers, Chapman, ISBN 978-1260084177. Unbedingt die ISBN beachten, es gibt zwei Versionen einmal für den internationalen Markt und einmal für den US Markt. Die letztere Version ist gut viermal zu teuer wie die internationale Version. Die ältere Fortran 2003 Version ist auch ausreichend, da man die restlichen Unterschiede über die Änderungspapiere der ISO Arbeitsgruppe nachlesen kann.
  • Modern Fortran explained, Metcalf, ISBN 978-0198811886. Auch hier beachten, dass es verschiedene Versionen gibt. Die Paperback Version ist ausreichend.
Wellenbrett
gfhfkgfhfk
Danke für die ausführliche Antwort! Interessant, diese drei Phasen von Fortran so klar zu unterscheiden; auch dass es inzwischen objektorientiert ist, war mir vollkommen neu. Die Syntax im Code von ChatGPT oben wirkt auf mich irgendwie simpel, als gäbe es wenig abstrakte Konzepte in der Sprache, aber das kann natürlich täuschen.
Ich hatte vor einiger Zeit aus Spielerei eine Klasse für eine doppelte verlinkte Liste in Fortran geschrieben. Normalerweise braucht man so etwas in Fortran eigentlich nicht, und generell stellt sich die Frage ob man solche Listen überhaupt braucht. Aber da es zeigt sehr schön was man mitterweile in Fortran umsetzen kann. Allerdings meckert valgrind noch herum, dass es ein Problem gibt. Irgend was passt noch nicht.

Die Indirektion im Testprogramm ist notwendig, weil sonst das RAII nicht funktioniert. Das ist so eine Besonderheit.
module doubly_linked_list
    use iso_fortran_env
    implicit none
    private
    public :: node, list, node_create

    type :: node
        class(*), allocatable, public :: value
        class (node), pointer, private :: prevptr => null(), nextptr => null()
    contains
        procedure, pass, non_overridable :: next => node_next
        procedure, pass, non_overridable :: prev => node_prev

        final :: node_destruct
    end type node

    type :: list
        class (node), pointer, private :: headptr => null(), tailptr => null()
    contains
        procedure, pass, non_overridable :: add_tail => list_add_tail
        procedure, pass, non_overridable :: add_head => list_add_head
        procedure, pass, non_overridable :: delete => list_delete
        procedure, pass, non_overridable :: head => list_head
        procedure, pass, non_overridable :: tail => list_tail

        final :: list_destruct
    end type list
contains
    function node_create (data) result (new_node)
        class (node), pointer :: new_node
        class (*), intent(in) :: data
        integer :: error

        new_node => null()

        allocate (new_node, STAT=error)
        if (0 /= error) then
            write (error_unit,*) 'cannot allocate'
            stop
        end if

        allocate (new_node%value, STAT=error, SOURCE=data)
        if (0 /= error) then
            write (error_unit,*) 'cannot allocate'
            stop
        end if
    end function node_create

    function node_next (this) result (next_node)
        class (node), pointer :: next_node
        class (node) :: this
        
        next_node => this%nextptr
    end function node_next

    function node_prev (this) result (prev_node)
        class (node), pointer :: prev_node
        class (node) :: this

        prev_node => this%prevptr
    end function node_prev

    subroutine node_destruct (this)
        type (node) :: this

        this%nextptr => null()
        this%prevptr => null()
        deallocate(this%value)
    end subroutine node_destruct

    subroutine list_add_tail (this, node_pointer)
        class (list) :: this
        class (node), pointer, intent(in) :: node_pointer

        if (.NOT.associated(this%tailptr)) then
            this%tailptr => node_pointer
            this%headptr => node_pointer
        else
            node_pointer%prevptr => this%tailptr
            node_pointer%nextptr => null()
            this%tailptr => node_pointer
        end if
    end subroutine list_add_tail

    subroutine list_add_head (this, node_pointer)
        class (list) :: this
        class (node), pointer, intent (in) :: node_pointer

        if (.NOT.associated(this%headptr)) then
            this%headptr => node_pointer
            this%tailptr => node_pointer
        else
            node_pointer%nextptr => this%headptr
            node_pointer%prevptr => null()
            this%headptr => node_pointer
        end if
    end subroutine list_add_head

    subroutine list_delete (this)
        class (list) :: this

        type (node), pointer :: p1 => null(), p2 => null()

        p1 => this%headptr
        if (associated(p1)) then
            do

                p2 => p1%nextptr
                p1%nextptr => null()
                p1%prevptr => null()
                deallocate (p1)

                if (.NOT.associated(p2)) then
                    exit
                end if

                p1 => p2
            end do

            this%headptr => null()
            this%tailptr => null()
        end if
    end subroutine list_delete

    subroutine list_destruct (this)
        type (list) :: this

        call this%delete
    end subroutine list_destruct

    function list_head (this) result (node_ptr)
        class (list) :: this
        class (node), pointer :: node_ptr

        node_ptr => this%headptr
    end function list_head

    function list_tail (this) result (node_ptr)
        class (list) :: this
        class (node), pointer :: node_ptr

        node_ptr => this%tailptr
    end function list_tail
end module doubly_linked_list
Dann gibt es noch ein Testprogramm dazu.
program doubly_linked_list_test
    implicit none

    type :: my_data
        integer :: number
        integer :: serial
    end type my_data

    type :: my_data2
        integer:: code
    end type my_data2

    call main
contains
    subroutine main
        use doubly_linked_list
        use iso_fortran_env
        implicit none

        type (my_data) :: data1, data2
        type (my_data2) :: data3
        type (list) :: my_list
        type (node), pointer :: a_node

        data1%number = 1
        data1%serial = 1

        data2%number = 1
        data2%serial = 2

        data3%code = -5
    
        a_node => node_create (data1)

        call my_list%add_head (a_node)

        a_node => null()
        a_node => node_create (data2)

        call my_list%add_head (a_node)
        a_node => null()
        
        a_node => node_create (data3)
        call my_list%add_head (a_node)

        a_node => my_list%head ()

        a_node => null()
        data1%serial = 3
        a_node => node_create (data1)

        call my_list%add_tail (a_node)
    end subroutine main
end program doubly_linked_list_test
0

Kommentieren

Diese Diskussion ist bereits mehr als 3 Monate alt und kann daher nicht mehr kommentiert werden.