[英]Reading a known number of variable from a file when one of the variables are missing in input file
我已經檢查過類似的帖子。 MSB 在這里給出了解決方案Reading data file in Fortran with known number of lines but unknown number of entries in each line
所以,我遇到的問題是我試圖從文本文件中讀取輸入。 在一行中應該有 3 個變量。 但有時輸入文件可能有 2 個變量。 在那種情況下,我需要將最后一個變量設為零。 我嘗試將 READ 語句與 IOSTAT 一起使用,但如果只有兩個值,它會轉到下一行並讀取下一個可用值。 當沒有第三個值時,我需要在讀取 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
我不能使用 MSB 建議的字符串方法。 還有別的辦法嗎?
我似乎記得過去曾嘗試做類似的事情。 如果您知道文件一行的大小不會超過某個數字,您可以嘗試以下操作:
...
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 標准中閱讀它......
我有一個計算一條線上實數的例程。 我認為您可以很容易地將其適應您的目的。
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
如果 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”開始的字符串“string”中讀取下一個實數,並返回“value”中的值。 如果已到達字符串末尾,則將“pos”設置為零(並返回值 0.0),否則將“pos”遞增到讀取的實數后面的字符 position。
因此,對於您的情況,您首先會將該行讀入一個字符串:
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
最后的'if'甚至不是必需的(但這樣它更透明恕我直言)。
請注意,如果該行中的第三個條目不是實數,則此技術將失敗。
您也許可以使用命名精美的冒號編輯描述符。 如果 I/O 列表中沒有其他項目,這允許您跳過格式的 rest:
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 或評論未被閱讀,它們是否保證分別為 0 和所有空格? 不確定,需要去別處問。
我知道以下簡單的解決方案:
w = 0.0
read(15,*,err=600)y, z, w
goto 610
600 read(15,*)y, z
610 do other stuff
但它包含“goto”運算符
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.