繁体   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