2015-08-15 22 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中的數字。