2012-04-10 28 views
1

我已經檢查過類似的帖子。解決方案是由M. S. B.在這裏Reading data file in Fortran with known number of lines but unknown number of entries in each line當輸入文件中有一個變量丟失時,從文件中讀取已知數量的變量

所以,我遇到的問題是,從文本文件我試圖讀取輸入。在一行中應該有3個變量。但有時輸入文件可能有2個變量。在這種情況下,我需要使最後一個變量爲零。我嘗試在IOSTAT中使用READ語句,但如果只有兩個值,它會轉到下一行並讀取下一個可用值。當沒有第三個值時,我需要在讀取2個值後停止在第一行。

我發現一種方法是讓一個評論/除了我試圖讀取的類型(在這種情況下,我閱讀的浮點數,而評論是一個字符)這使得IOSTAT> 0,我可以用它作爲支票。但是如果在某些情況下我可能沒有那個評論。我想確保它甚至比它更有效。代碼

read(15,*) x 
    read(15,*,IOSTAT=ioerr) y,z,w 
    if (ioerr.gt.0) then 
     write(*,*)'No value was found' 
     w=0.0; 
     goto 409 
     elseif (ioerr.eq.0) then 
     write(*,*)'Value found', w 
     endif 
    409 read(15,*) a,b 
     read(15,*) c,d 

輸入文件的

部分是形式

-1.000 abcd                   
    12.460 28.000 8.00 efg                    
    5.000 5.000 hijk                    
    20.000 21.000 lmno                    

我需要做,即使沒有「8.00 EFG」

這種情況下,它工作的

-1.000 abcd                   
    12.460 28.000                    
    5.000 5.000 hijk                    
    20.000 21.000 lmno 

I ca n不使用MSB建議的字符串方法。有沒有其他方法?

+0

另一個想法,但沒有提到,就是預處理與寫的是一種語言的腳本輸入文件更適合這類任務(python,perl甚至awk想起來)......看起來這種方法會更簡單和更強大。 – mgilson 2012-04-11 11:43:10

+0

這是一個完美的建議。但是,我正在編寫20年前編寫的代碼,此時無法更改輸入文件格式。 – jonayat 2012-04-11 15:14:47

+0

我並不是建議你改變輸入文件的(預期)格式,只使用腳本將原始格式不正確的文件打包成符合你的代碼(20年前寫的)所需的文件。 – mgilson 2012-04-11 16:21:54

回答

0

我似乎記得在過去嘗試做類似的事情。如果你知道一個行的文件的大小將不超過一定數目,你也許可以嘗試類似:

... 
character*(128) A 

read(15,'(A128)') A !This now holds 1 line of text, padded on the right with spaces 
read(A,*,IOSTAT=ioerror) x,y,z 
if(IOSTAT.gt.0)then 
    !handle error here 
endif 

我不能完全肯定這個解決方案如何便攜式是從一個編譯器到下一個,我現在沒有時間閱讀它的f77標準...

0

我有一個例程,計算一個線上的實數。我認爲你可以很容易地適應你的目的。

subroutine line_num_columns(iu,N,count) 
    implicit none 

    integer(4),intent(in)::iu,N 

    character(len=N)::line 
    real(8),allocatable::r(:) 
    integer(4)::r_size,count,i,j 

    count=0 !Set to zero in case of premature return 

    r_size=N/5 !Initially try out this max number of reals 
    allocate(r(r_size)) 

    read(iu,'(a)') line 

50 continue 
    do i=1,r_size 
     read(line,*,end=99) (r(j),j=1,i) !Try reading i reals 
     count=i 
     !write(*,*) count 
    enddo 
    r_size=r_size*2 !Need more reals 
    deallocate(r) 
    allocate(r(r_size)) 
    goto 50 

    return 

99 continue 
    write(*,*) 'I conclude that there are ',count,' reals on the first line' 


end subroutine line_num_columns 
+0

謝謝,我會試試這個。 – jonayat 2012-04-11 06:38:24

+0

這個計數非常漂亮,我忘記了最後的說明符。 (現在我想到了,我應該也可以在我的回答中使用它)。你應該提到的一件事是,在你計算了線上的實數之後,你需要「退格」這個單位以便能夠真正獲得實數。 – mgilson 2012-04-11 16:19:06

+0

@mgilson:那是真的。但不是'退格',我只是將這個例程調整到他的特定目的,並返回數組'r'和'count'。我從不相信Fortran中的文件運動。 – bdforbes 2012-04-12 03:26:20

0

如果一個Fortran 90的解決方案是好的,你可以使用下面的步驟來解析與多個真實值的線條:

subroutine readnext_r1(string, pos, value) 
    implicit none 
    character(len=*), intent(in) :: string 
    integer,   intent(inout) :: pos 
    real,    intent(out) :: value 

    integer       :: i1, i2 

    i2 = len_trim(string) 

    ! initial values: 
    if (pos > i2) then 
    pos = 0 
    value = 0.0 
    return 
    end if 

    ! skip blanks: 
    i1 = pos 
    do 
    if (string(i1:i1) /= ' ') exit 
    i1 = i1 + 1 
    end do 

    ! read real value and set pos: 
    read(string(i1:i2), *) value 
    pos = scan(string(i1:i2), ' ') 
    if (pos == 0) then 
    pos = i2 + 1 
    else 
    pos = pos + i1 - 1 
    end if 

end subroutine readnext_r1 

子程序讀取一個字符串「字符串」下一個實數從字符數字'pos'開始,並返回'value'中的值。如果已到達字符串的末尾,則將'pos'設置爲零(並返回值爲0.0),否則'pos'會增加到讀取的實數後面的字符位置。

因此,對於你的情況,你會先閱讀行字符串:

character(len=1024) :: line 
... 
read(15,'(A)') line 
... 

,然後解析這個字符串

real :: y, z, w 
integer :: pos 
... 
pos = 1 
call readnext_r1(line, pos, y) 
call readnext_r1(line, pos, z) 
call readnext_r1(line, pos, w) 
if (pos == 0) w = 0.0 

,其中最終「如果」甚至沒有必要(但這種方式是更透明的imho)。

請注意,如果行中有第三個條目不是實數,則此技術將失敗。

0

您可以使用奇妙的冒號編輯描述符。這允許您是否有在I/O列表中沒有任何進一步的項目跳過格式的休息:

Program test 

    Implicit None 

    Real :: a, b, c 
    Character(Len = 10) :: comment 


    Do 

    c = 0.0 
    comment = 'No comment' 
    Read(*, '(2(f7.3, 1x), :, f7.3, a)') a, b, c, comment 

    Write(*, *) 'I read ', a, b, c, comment 

    End Do 

End Program test 

例如與gfortran我得到:

Wot now? gfortran -W -Wall -pedantic -std=f95 col.f90 
Wot now? ./a.out 
    12.460 28.000 8.00 efg 
I read 12.460000  28.000000  8.0000000  efg  
    12.460 28.000 
I read 12.460000  28.000000  0.00000000E+00   
^C 

這適用於gfortran,G95 ,NAG編譯器,Intel編譯器和Sun/Oracle編譯器。不過,我應該說我並不完全相信我明白這一點 - 如果c或comment不被讀取,它們分別保證爲0和所有空格?不確定,需要詢問其他地方。

0

我知道下面的簡單的解決方案:

 w = 0.0 
     read(15,*,err=600)y, z, w 
     goto 610 
600 read(15,*)y, z 
610 do other stuff 

但它包含「轉到」運營商

+0

您可以輕鬆避免轉到。只需使用iostat和do循環。 – 2017-05-18 20:22:31