AmphotericLewisAcid
AmphotericLewisAcid

Reputation: 2299

How do you detect blank lines in Fortran?

Given an input that looks like the following:

123
456
789

42
23
1337

3117

I want to iterate over this file in whitespace-separated chunks in Fortran (any version is fine). For example, let's say I wanted to take the average of each chunk (e.g. mean(123, 456, 789) then mean(42, 23, 1337) then mean(31337)).

I've tried iterating through the file normally (e.g. READ), reading in each line as a string and then converting to an int and doing whatever math I want to do on each chunk. The trouble here is that Fortran "helpfully" ignores blank lines in my text file - so when I try and compare against the empty string to check for the blank line, I never actually get a .True. on that comparison.

I feel like I'm missing something basic here, since this is a typical functionality in every other modern language, I'd be surprised if Fortran didn't somehow have it.

Upvotes: 0

Views: 860

Answers (2)

lastchance
lastchance

Reputation: 6640

Just read each line as a character (but note Francescalus's comment on the format). Then read the character as an internal file.

program stuff
   implicit none
   integer io, n, value, sum
   character (len=1000) line

   n = 0
   sum = 0
   io = 0
   open( 42, file="stuff.txt" )
   do while( io == 0 )
      read( 42, "( a )", iostat = io ) line
      if ( io /= 0 .or. line == "" ) then
         if ( n > 0 ) print *, ( sum + 0.0 ) / n
         n = 0
         sum = 0
      else
         read( line, * ) value
         n = n + 1
         sum = sum + value
      end if
   end do

   close( 42 )

end program stuff
456.000000    
467.333344    
3117.00000    

Upvotes: 2

Federico Perini
Federico Perini

Reputation: 1416

If you're using so-called "list-directed" input (format = '*'), Fortran does special handling to spaces, commas, and blank lines.

To your point, there's a feature which is using the BLANK keyword with read

read(iunit,'(i10)',blank="ZERO",err=1,end=2) array

You can set:

  • blank="ZERO" will return a valid zero value if a blank is found;
  • blank="NULL" is the default behavior that skips blank/returns an error depending on the input format.

If all your input values are positive, you could use blank="ZERO" and then use the location of zero values to process your data.

EDIT as @vladimir-f has correctly pointed out, you not only have blanks in between lines, but also after the end of the numbers in most lines, so this strategy will not work.

You can instead load everything into an array, and process it afterwards:

program array_with_blanks
      integer :: ierr,num,iunit
      integer, allocatable :: array(:)
   
  open(newunit=iunit,file='stackoverflow',form='formatted',iostat=ierr)
      allocate(array(0))
      do
         read(iunit,'(i10)',iostat=ierr) num
         if (is_iostat_end(ierr)) then
            exit
         else
            array = [array,num]
         endif
      end do
      close(iunit)
      print *, array
end program

Upvotes: 2

Related Questions