2016-06-30 14 views
3

Ich bin mit 90 Fortran eine Datei zu lesen, die Daten in folgendem FormatFortran lesen gemischten Text und Zahlen

number# 125 var1= 2 var2= 1 var3: 4 
     . 
     . 
     . 
     . 
number# 234 var1= 3 var2= 5 var3: 1 

Ich habe versucht, den folgenden Befehl ein und funktioniert gut

read (2,*) tempstr , my_param(1), tempstr , my_param(2), tempstr , my_param(3) 

Problem enthält, wenn die Zahlen werden größer und es gibt keinen Abstand zwischen String und Zahl, dh die Daten sehen wie folgt aus:

number# 125 var1= 2 var2=124 var3: 4 

Ich habe versucht,

 read (2,512) my_param(1), my_param(2), my_param(3) 

512 format('number#', i, 'var1=', i, 'var2=', i, 'var3:', i) 

Es liest alle Zahl als Null

ich nicht zu einer anderen Sprache wechseln. Der Datensatz ist riesig, daher kann ich ihn nicht vorverarbeiten. Außerdem sind die Trennzeichen nicht jedes Mal gleich. Kann jemand bitte mit dem Problem helfen? nicht zu viel für die Vorverarbeitung

Vielen Dank im Voraus

+0

880.000 MB, 720.000 Zeilen. Wie Sie in den Beispieldaten sehen können, wird den Nummern "#", "=" oder ":" vorangestellt. Es ist nicht das gleiche Symbol, das vor den Zahlen auftritt. –

+0

Können Sie bitte etwas vorschlagen? Vielleicht ein Beispiel Code –

+0

Wie Sie in den Beispieldaten sehen können, Nummern vorangestellt sind "#", "=" oder ":". Es ist nicht das gleiche Symbol, das vor den Zahlen auftritt. –

Antwort

2

Während ich immer noch mit meiner ursprünglichen Antwort, partic Gerade weil die Eingabedaten schon so nah beieinander liegen, wie eine Namenslistendatei aussehen würde, nehmen wir an, dass Sie die Daten vorher nicht wirklich vorverarbeiten können.

Die nächste beste Sache ist, die gesamte Zeile in eine character(len=<enough>) Variable einzulesen, dann extrahieren Sie die Werte aus dem mit String Manipulation. So etwas wie dieses:

program mixed2 
    implicit none 
    integer :: num, val1, val2, val3 
    character(len=50) :: line 
    integer :: io_stat 

    open(unit=100, file='data.dat', action='READ', status='OLD') 
    do 
     read(100, '(A)', iostat=io_stat) line 
     if (io_stat /= 0) exit 
     call get_values(line, num, val1, val2, val3) 
     print *, num, val1, val2, val3 
    end do 
    close(100) 

    contains 

     subroutine get_values(line, n, v1, v2, v3) 
      implicit none 
      character(len=*), intent(in) :: line 
      integer, intent(out) :: n, v1, v2, v3 
      integer :: idx 

      ! Search for "number#" 
      idx = index(line, 'number#') + len('number#') 

      ! Get the integer after that word 
      read(line(idx:idx+3), '(I4)') n 

      idx = index(line, 'var1') + len('var1=') 
      read(line(idx:idx+3), '(I4)') v1 

      idx = index(line, 'var2') + len('var3=') 
      read(line(idx:idx+3), '(I4)') v2 

      idx = index(line, 'var3') + len('var3:') 
      read(line(idx:idx+3), '(I4)') v3 
     end subroutine get_values 
end program mixed2 

Bitte beachten Sie, dass ich keine Fehler/Gesundheitsprüfung enthalten habe. Das überlasse ich dir.

+0

vielen dank :) –

3

First up, 720.000 Zeilen ist. Werkzeuge wie sed und awk arbeiten meist Zeile für Zeile, also skalieren sie wirklich gut.

Was ich tatsächlich getan haben, war es, die Daten so zu konvertieren, dass ich Namenslisten verwenden:

$ cat preprocess.sed 

# Add commas between values 
# Space followed by letter -> insert comma 
s/ \([[:alpha:]]\)/ , \1/g 

# "number" is a key word in Fortran, so replace it with num 
s/number/num/g 

# Replace all possible data delimitors with the equals character 
s/[#:]/=/g 

# add the '&mydata' namelist descriptor to the beginning 
s/^/\&mydata /1 

# add the namelist closing "/" character to the end of the line: 
s,$,/,1 

$ sed -f preprocess.sed <data.dat> data.nml 

Überprüfen Sie, ob die Daten korrekt vorverarbeitet wurde:

$ tail -3 data.dat 
number#1997 var1=114 var2=130 var3:127 
number#1998 var1=164 var2=192 var3: 86 
number#1999 var1=101 var2= 48 var3:120 

$ tail -3 data.nml 
&mydata num=1997 , var1=114 , var2=130 , var3=127/ 
&mydata num=1998 , var1=164 , var2=192 , var3= 86/ 
&mydata num=1999 , var1=101 , var2= 48 , var3=120/ 

Dann können Sie lesen es mit diesem Fortran-Programm:

program read_mixed 
    implicit none 
    integer :: num, var1, var2, var3 
    integer :: io_stat 
    namelist /mydata/ num, var1, var2, var3 

    open(unit=100, file='data.nml', status='old', action='read') 
    do 
     read(100, nml=mydata, iostat=io_stat) 
     if (io_stat /= 0) exit 
     print *, num, var1, var2, var3 
    end do 
    close(100) 
end program read_mixed 
Verwandte Themen