I would like to read a sequence of integer in a line with unknown bound in FORTRAN. My question is similar to the following previous post,
Reading a file of lists of integers in Fortran
however I want to read a sequence of unknown numbers of integer in a line and save it in separate arrays. And successive lines of integer should be saved to some other array
My file looks like this
5 7 8 9 10 13 # should be stored f(1)(6) arrays
93 102 92 # c(1)(3)
105 107 110 145 147 112 # f(2)(6)
97 98 # b(1)(2)
12 54 55 # c(2)(3)
15 17 21 23 45 # e(1)(5)
43 47 48 51 62 # d(1)(4)
Thus I have a sequence of integers with maximum length of 6 (to be stored in f array) and minimum length of 2(to be stored in b array). I have hundreds of lines like this, such that I need to classify according to the maximum length and count on them.
There are probably many ways to do this, and the following is one such example. Here, the split() makes multiple trials for list-directed input for all values in the line, until non-numeric characters or the end of line is encountered.
subroutine split( line, vals, n )
implicit none
character(*), intent(in) :: line
real*8 :: vals(*), buf( 100 ) !! currently up to 100 items (for test)
integer :: n
n = 1
do
read( line, *, end=100, err=100 ) buf( 1 : n ) !! (See Appendix for why buf is used here)
vals( 1:n ) = buf( 1:n )
n = n + 1
enddo
100 continue
n = n - 1
end
program main
implicit none
character(200) :: line
real*8 :: vals( 100 )
integer :: n
open( 10, file="test.dat", status="old" )
do
read( 10, "(a)", end=500 ) line
call split( line, vals, n )
if ( n == 0 ) then
print *, "comment line"
else
print *, nint( vals( 1 : n ) )
endif
enddo
500 continue
close( 10 )
end
If test.dat contains the whole lines in the Question, plus the following lines
# additional data
1,2,3 , 4 , 5 # comma-separated integers
1.23e2 -4.56e2 , 777 # integer/floating-point mixed case
it gives
comment line
5 7 8 9 10 13
93 102 92
105 107 110 145 147 112
97 98
12 54 55
15 17 21 23 45
43 47 48 51 62
comment line
1 2 3 4 5
123 -456 777
So one can save the result for each line by copying the values in vals(1:n)
to a desired array.
[ Appendix (thanks to @francescalus) ]
In the above code, the data are read once into buf(1:n)
and then copied to vals(1:n)
. One might think that it would be more direct to read in the data into vals(1:n)
such that
read( line, *, end=100, err=100 ) vals( 1 : n )
However, this direct approach is not recommended because vals(1:n)
becomes undefined when the read statement hits the "end" or "err" condition. Although ifort and gfortran seem to retain the data in vals(1:n)
even when that condition is met (and so they work even with the direct approach), the same behavior cannot be guaranteed for other compilers. In contrast, the buffer approach avoids this risk by saving the data one step before to vals(1:n)
, so that undefined data are not used. This is why the buffer approach is used in the above code despite it is one statement longer.