可能有很多方法可以做到这一点,下面是一个这样的例子。在这里,split() 对行中所有值的列表导向输入进行多次尝试,直到遇到非数字字符或行尾。
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
如果 test.dat 包含问题中的整行,加上以下行
# additional data
1,2,3 , 4 , 5 # comma-separated integers
1.23e2 -4.56e2 , 777 # integer/floating-point mixed case
它给了
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
因此可以通过将vals(1:n) 中的值复制到所需的数组来保存每一行的结果。
[ 附录(感谢@francescalus)]
在上面的代码中,数据被读入一次buf(1:n),然后复制到vals(1:n)。有人可能会认为将数据读入vals(1:n) 会更直接,这样
read( line, *, end=100, err=100 ) vals( 1 : n )
但是,不建议使用这种直接方法,因为当 read 语句遇到“end”或“err”条件时,vals(1:n) 变得未定义。尽管 ifort 和 gfortran 似乎保留了 vals(1:n) 中的数据,即使满足该条件(因此即使使用直接方法它们也可以工作),但不能保证其他编译器具有相同的行为。相比之下,缓冲区方法通过将前一步的数据保存到vals(1:n) 来避免这种风险,因此未使用未定义的数据。这就是为什么在上面的代码中使用缓冲区方法的原因,尽管它是一个语句。