Search code examples
fortranreadfilefortran90

Fortran read mixed text and numbers


I am using Fortran 90 to read a file that contains data in the following format

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

I tried the following command and works fine

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

Problem is when the numbers become larger and there is no space between string and number, i.e. the data looks as following:

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

I tried

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

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

It reads all number as zero

I can't switch to some other language. The data set is huge, so I can't pre-process it. Also, the delimiters are not the same every time. Can someone please help with the problem?

Thanks in advance


Solution

  • While I still stand with my original answer, particularly because the input data is already so close to what a namelist file would look like, let's assume that you really can't make any preprocessing of the data beforehand.

    The next best thing is to read in the whole line into a character(len=<enough>) variable, then extract the values out of that with String Manipulation. Something like this:

    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
    

    Please note that I have not included any error/sanity checking. I'll leave that up to you.