2015-08-15 59 views
1

束缚我想用FORTRAN约束未知行改为整数序列。我的问题是类似于下面的以前的帖子,读整数序列与未知线FORTRAN

Reading a file of lists of integers in Fortran

不过我想读一列整数的未知数字的序列,并将其保存在单独的数组。和整数的连续行应该被保存到一些其它阵列

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) 

因此我有整数为6的最大长度(以存储f中阵列)和的2的最小长度的序列(将要存储在B数组)。我有这样的数百行,这样我需要根据最大长度进行分类并计数。

Reading a file of lists of integers in Fortran

回答

2

可能有许多方法可以做到这一点,以下就是这样一个例子。在这里,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)来避免此风险,以便未使用未定义的数据。这就是为什么上述代码使用缓冲方法的原因,尽管它只有一个陈述更长。

1

像这样的东西可能会满足您的要求

INTEGER :: ix, rdstat 
    INTEGER, DIMENSION(6) :: nums 
    CHARACTER(len=128) :: aline 
    ... 
    OPEN(21,file='data.txt') 

    DO ix = 1,10 
    READ(21,'(a)',iostat=rdstat) aline 
    IF (rdstat/=0) catch_errors() 

    nums = -99 ! a guard 
    READ(aline,*,iostat=rdstat) nums 
    IF (rdstat/=0) catch_errors() 
    ! do something with nums 
    END DO 

    CLOSE(21) 

我还没有彻底测试这一点,我没有写catch_errors你 - 在实践中你可能不想做的非常多。这第一个版本可能太脆弱了,但是否合适,很大程度上取决于输入文件的一致性(或其他方面)。

策略是将读取的每个线到一个字符变量(一个用于整行足够长的时间),然后使用内部,表式,读取从字符变量的开始读6点的整数。这利用了列表导向输入具有在空间分隔值的输入流中找到整数的内置设施。这种方法应该用逗号分隔的整数列表来工作。内部只读查找6个整数,然后在找不到更多整数时捕获错误,或仅查找不能解释为整数的材料(例如像# comment这样的字符串)。

  • 我已经承担了128个字符的最大行长度,您可能需要来调整。
  • 我已经指定了程序将读取的行数的固定上限。您可能需要更改该设置,或更改为do/while循环。
  • 该程序预计不超过6个整数作为您的问题指定。
  • 在每一行读取数组nums在每个元素填充-99;这是一个'警卫'。如果-99很可能发生在您的输入文件中,您可能需要更改它。
  • 完全取决于你如何处理nums中的数字。