【问题标题】:Fortran read multi-line recordFortran 读取多行记录
【发布时间】:2012-05-11 09:09:23
【问题描述】:

我有一个旧的 Fortran 程序,用于从文本文件中读取记录。记录格式为:

record_type field1 field2 ... fieldN ;

这些记录可能分布在多行,字符 ;表示记录已经结束。旧代码是:

2 read(data,"(a130)",end=3)line
  shift=adrec(nbrec)-1
  read(line,*,end=1)typrec(nbrec),(field(shift+i),i=1,65)
1 do
    do j=shift+1,shift+i-1
      k=index(field(j),';')
      if(k .ne. 0)then
        if(k .eq. 1)then
          adrec(nbrec+1)=j
        else
          field(j)(k:)=''
          adrec(nbrec+1)=j+1
        endif
          go to 2
      endif
    endo
    read(data,"(a130)")line
    read(line,*,end=1)(field(shift+i),i=1,65)
  enddo
3 continue

此代码原样与英特尔编译器 (ifort) 一起使用。使用 gfortran 它失败了!第一个问题是第三行的隐式读取,使用 ifort,使 i 等于实际读取的字段数,而在 gfortran 中它总是给出 65。第二个问题是在相同的隐式读取中,使用 ifort , 性格 ;被读取为普通字段,但 gfortran 被跳过。

谁能帮我解决这两个问题?也欢迎任何其他将代码全部替换的想法。

【问题讨论】:

  • 替换代码的好主意取决于更清楚地了解您正在阅读的数据类型。我猜 record_type 是某种代码(整数?字符?),字段是实数吗?整数?混合物 ? record_type 是否决定了记录中的字段类型和字段个数?
  • record_type 和字段都是字符(character*20 typrec(mxrecord), field(mxfield))。之后根据记录的类型通过 read(field(i),*)var 处理它们。因此,var 是实数、整数或字符,具体取决于 i 对于此类记录的含义。

标签: fortran gfortran intel-fortran


【解决方案1】:

这行得通吗?除了do while(和exit 控制结构...)之外,这是符合f77 的(我认为)。如果需要,do while 可以相对容易地被 goto/continue 替换。我不知道您最终希望字符串是什么类型,所以我返回字符串(并假设字段不能超过 24 个字符)......我还假设“行”不能超过 1024人物。 很抱歉缺少 cmets,但我认为函数名称具有足够的描述性。一般来说,我认为在编程时使用函数/子例程是个好主意,因为这会使代码更具可读性......

  program main
  character*1024 line
  integer stat,stat2,i,nf
  character*24 fld
  character*16 fmt

  open(unit=21,file='test.dat',status='old')
  stat=0
  do while(stat.eq.0)
     call readline(21,line,stat)
     stat2=0
     i=1
     do while(.true.)
        call getfield(line,fld,stat2)
        if(stat2.ne.0) exit
        i=i+1
        write(*,*) i,stat2,fld
     enddo
     write(*,*) " "
  enddo


  end

  subroutine getfield(line,field,stat)
  integer l,i,stat
  character*(*) line,field
  !Get first field and shift the line
  l=1
  if(line.eq.' ')then
     stat=1
  else
     stat=0
  endif
  do while (line(l:l).eq.' ')
     l=l+1
  enddo
  i=l
  do while (line(i:i).ne.' ')
     i=i+1
  enddo

  if((line(l:l).eq.'"').or.(line(l:l).eq."'"))then
     do while(line(i:i).ne.line(l:l))
        i=i+1
     enddo
  endif

  field=line(l:i)
  line=line(i+1:)
  return
  end

  subroutine readline(unit,line,stat)
  integer unit
  character*(*) line
  integer stat,i
  !read one "line"  Lines are sequences seperated by ';' (can have newlines in there) 

  stat=0
  i=1
  do while (.true.)
     read(unit,'(A)',end=100) line(i:)
     i=index(line,';')
     if(i.eq.0)then
        i=len_trim(line)+2
     else
        line(i:)=' ' !remove the trailing semicolon.
        exit
     endif
  enddo

  return
 100  continue
  stat=1
  return
  end

【讨论】:

  • readline 子程序看起来很不错!只有一个问题。要获取字段,请使用 read ,因为某些字段内部有空格并用“ ”标记。例如,“1013 1014”应作为一个字段读取。 read 语句会处理这个问题。我将尝试将您的建议合并到代码中,并以某种方式更改 getfield 以处理“”中的字段。如果您对此有任何想法,欢迎!
  • @p3tris -- 它们是否保证是 '' 或者它们可以是 ""?
  • @p3tris -- 我已经编辑过了。试试上面的代码(我没有测试过)。基本上我只是测试了第一个字符是否是'或'然后在getfield中寻找结束'或'。另外,我说代码大多符合 f77 标准,但我忘记了我也使用了名称中超过 6 个字符的子例程......哦,好吧。
  • 那部分代码是 f77 但一般来说其余的代码甚至有 f2003 的特性。所以,它不需要与 f77 兼容(对不起,如果我误导了你)。我认为修改后的代码应该可以解决问题!我会尝试在今晚之前对其进行编码并回复您。非常感谢您的宝贵时间!
  • 对一些测试数据进行了尝试。与 ifort 和 gfortran 完美搭配!非常感谢!现在,是时候将它合并到主程序中了……(我需要包括对有效记录的一些检查)。谢谢!
猜你喜欢
  • 2018-08-10
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多