可能有许多方法可以做到这一点,以下就是这样一个例子。在这里,split()对列表中的所有值进行列表定向输入的多次尝试,直到遇到非数字字符或行尾。
subroutine split(line, vals, n)
implicit none
character(*), intent(in) :: line
real*8 :: vals(*), buf(10000)
integer :: n
n = 1
do
read(line, *, end=100, err=100) buf(1 : n) !! (See Appendix for why buf is used here)
val(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(10000)
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),然后复制到val(1:n)。有人可能会认为,这将是更为直接的数据读入VAL(1:N),使得
read(line, *, end=100, err=100) val(1 : n)
但是,不建议使用这种直接的方法,因为VAL(1:N)是不确定的,当读语句触发“结束”或“错误”条件。虽然ifort和gfortran似乎仍然保留val(1:n)中的数据,即使满足该条件(因此即使采用直接方法也能工作),但其他编译器无法保证相同的行为。相比之下,缓冲方法通过将数据先前保存到val(1:n)来避免此风险,以便未使用未定义的数据。这就是为什么上述代码使用缓冲方法的原因,尽管它只有一个陈述更长。