簡體   English   中英

當輸入文件中缺少一個變量時,從文件中讀取已知數量的變量

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM