15

我的任务是编写一个 Fortran 95 程序,该程序将从文件中读取字符输入,然后(开始)简单地将其再次吐出。棘手的部分是这些输入行的长度不同(没有给出最大长度)并且文件中可以有任意数量的行。

我用过

    do
      read( 1, *, iostat = IO ) DNA    ! reads to EOF -- GOOD!!
      if ( IO < 0 ) exit               ! if EOF is reached, exit do
      I = I + 1
      NumRec = I                       ! used later for total no. of records
      allocate( Seq(I) )
      Seq(I) = DNA
      print*, I, Seq(I)
      X = Len_Trim( Seq(I) )           ! length of individual sequence
      print*, 'Sequence size: ', X
      print*
    end do

但是,我最初的陈述清单

    character(100), dimension(:), allocatable :: Seq
    character(100)  DNA

和适当的整数等。

我想我要问的是是否有任何方法不首先列出字符串的大小。假设我有一个 200 多个字符的 DNA 字符串,然后另一个只有 25 个字符,有没有一种方法可以让程序只读取其中的内容而不需要包含所有额外的空白?这可以在不需要使用的情况下完成len_trim吗,因为它不能在声明语句中引用?

4

4 回答 4

12

要在 Fortran 95 中逐步读取记录,请使用非高级输入。例如:

CHARACTER(10) :: buffer
INTEGER :: size
READ (unit, "(A)", ADVANCE='NO', SIZE=size, EOR=10, END=20) buffer

每次调用时将读取最多 10 个字符(缓冲区的长度)。一旦整个记录被一系列一个或多个非前进读取读取,文件位置只会前进到下一条记录(下一行)。

除非文件结束条件,size否则变量将定义为buffer每次执行 read 语句时读入的实际字符数。

EOREND说明符用于分别在记录结束或文件结束条件发生时控制执行流程(执行将跳转到适当标记的语句)。您也可以使用IOSTAT说明符来检测这些条件,但用于这两个条件的特定负值取决于处理器。

size您可以在特定记录中求和以计算出该特定记录的长度。

将这样的非高级读取包装在一个适当地检测文件结尾和记录结尾的循环中,并且您拥有增量读取部分。

在 Fortran 95 中,局部字符变量的长度规范必须是规范表达式 - 本质上是一个可以在包含变量声明的范围的第一个可执行语句之前安全评估的表达式。常量代表最简单的情况,但过程中的规范表达式可能涉及该过程的虚拟参数等。

读取任意长度的整个记录​​是一个多阶段的过程:

  • 通过使用一系列增量读取来确定当前记录的长度。当记录结束条件发生时,对特定记录的这些增量读取完成,此时文件位置将移动到下一条记录。
  • Backspace文件返回到感兴趣的记录。
  • 调用一个过程,将当前记录的长度作为虚拟参数传递。在该过程内部有一个字符变量,其长度由虚拟参数给出。
  • 在该调用过程中,使用正常的前进输入将当前记录读入该字符变量。
  • 对该字符变量进行进一步处理!

请注意,每条记录最终都会被读取两次——一次是为了确定它的长度,第二次是为了将数据实际读取到正确的“长度”字符变量中。

存在使用长度为 1 的可分配(或自动)字符数组的替代方法。总体策略是一样的。以常见的 ISO_VARYING_STRING 实现中的 Get 过程的代码为例。

Fortran 2003 引入了延迟长度字符变量,其长度可以由分配语句中的任意表达式指定,或者对于可分配变量,由赋值语句中右侧的长度指定。这(与其他“可分配”增强功能结合使用)允许确定记录长度的渐进式读取也可以构建保存记录内容的字符变量。您的主管需要更新他的 Fortran 环境。

于 2013-02-08T06:34:38.197 回答
11

这是 Fortran 2003 的一个函数,它设置一个与输入字符串长度完全相同的可分配字符串 (InLine)(可选修剪),或者返回 .false。如果文件结束

function ReadLine(aunit, InLine, trimmed) result(OK)
integer, intent(IN) :: aunit
character(LEN=:), allocatable, optional :: InLine
logical, intent(in), optional :: trimmed
integer, parameter :: line_buf_len= 1024*4
character(LEN=line_buf_len) :: InS
logical :: OK, set
integer status, size

OK = .false.
set = .true.
do
    read (aunit,'(a)',advance='NO',iostat=status, size=size) InS
    OK = .not. IS_IOSTAT_END(status)
    if (.not. OK) return
    if (present(InLine)) then
        if (set) then
            InLine = InS(1:size)
            set=.false.
        else
            InLine = InLine // InS(1:size)
        end if
    end if
    if (IS_IOSTAT_EOR(status)) exit
end do
if (present(trimmed) .and. present(InLine)) then
    if (trimmed) InLine = trim(adjustl(InLine))
end if

end function ReadLine

例如,用单位“aunit”对文件中的所有行做一些事情

 character(LEN=:), allocatable :: InLine

 do while (ReadLine(aunit, InLine))
   [.. something with InLine]
 end do
于 2014-02-22T11:23:35.030 回答
0

我使用了以下内容。让我知道它是否比您的更好或更差。

!::::::::::::::::::::: SUBROUTINE OR FUNCTION :::::::::::::::::::::::::::::::::::::::                                                                                                                                   
!__________________ SUBROUTINE lineread(filno,cargout,ios) __________________________                                                                                                                                   
subroutine lineread(filno,cargout,ios)                                                                                                                                                                                  
Use reallocate,ErrorMsg,SumStr1,ChCount                                                                                                                                                                                 
! this subroutine reads                                                                                                                                                                                                 
! 1. following row in a file except a blank line or the line begins with a !#*                                                                                                                                          
! 2. the part of the string until first !#*-sign is found or to end of string                                                                                                                                           
!                                                                                                                                                                                                                       
! input Arguments:                                                                                                                                                                                                      
! filno (integer)             input file number                                                                                                                                                                         
!                                                                                                                                                                                                                       
! output Arguments:                                                                                                                                                                                                     
! cargout (character)     output chArActer string, converted so that all unecessay spaces/tabs/control characters removed.                                                                                              

implicit none                                                                                                                                                                                                           
integer,intent(in)::filno                                                                                                                                                                                               
character*(*),intent(out)::cargout                                                                                                                                                                                      
integer,intent(out)::ios                                                                                                                                                                                                
integer::nlen=0,i,ip,ich,isp,nsp,size                                                                                                                                                                                   
character*11,parameter::sep='=,;()[]{}*~'                                                                                                                                                                               
character::ch,temp*100                                                                                                                                                                                                  
character,pointer::crad(:)                                                                                                                                                                                              

nullify(crad)                                                                                                                                                                                                           
cargout=''; nlen=0; isp=0; nsp=0; ich=-1; ios=0                                                                                                                                                                         
Do While(ios/=-1) !The eof() isn't standard Fortran.                                                                                                                                                                    
READ(filno,"(A)",ADVANCE='NO',SIZE=size,iostat=ios,ERR=9,END=9)ch ! start reading file                                                                                                                                  
! read(filno,*,iostat=ios,err=9)ch;                                                                                                                                                                                     
    if(size>0.and.ios>=0)then                                                                                                                                                                                           
     ich=iachar(ch)                                                                                                                                                                                                     
    else                                                                                                                                                                                                                
     READ(filno,"(A)",ADVANCE='no',SIZE=size,iostat=ios,EOR=9); if(nlen>0)exit                                                                                                                                          
    end if                                                                                                                                                                                                              
    if(ich<=32)then        ! tab(9) or space(32) character                                                                                                                                                              
        if(nlen>0)then                                                                                                                                                                                                  
     if(isp==2)then                                                                                                                                                                                                       
        isp=0;                                                                                                                                                                                                            
     else                                                                                                                                                                                                                 
        isp=1;                                                                                                                                                                                                            
     end if                                                                                                                                                                                                               
eend if; cycle;                                                                                                                                                                                                         
    elseif(ich==33.or.ich==35.or.ich==38)then !if char is comment !# or continue sign &                                                                                                                                 
     READ(filno,"(A)",ADVANCE='yes',SIZE=size,iostat=ios,EOR=9)ch; if(nlen>0.and.ich/=38)exit;                                                                                                                          
    else                                                                                                                                                                                                                
     ip=scan(ch,sep);                                                                                                                                                                                                   
     if(isp==1.and.ip==0)then; nlen=nlen+1; crad=>reallocate(crad,nlen); nsp=nsp+1; endif                                                                                                                               
     nlen=nlen+1; crad=>reallocate(crad,nlen); crad(nlen)=ch;                                                                                                                                                           
     isp=0; if(ip==1)isp=2;                                                                                                                                                                                             
    end if                                                                                                                                                                                                              
end do                                                                                                                                                                                                                  
9 if(size*ios>0)call ErrorMsg('Met error in reading file in [lineread]',-1)                                                                                                                                             
! ios<0: Indicating an end-of-file or end-of-record condition occurred.                                                                                                                                                 
if(nlen==0)return                                                                                                                                                                                                       
!write(6,'(a,l)')SumStr1(crad),eof(filno)                                                                                                                                                                               
!do i=1,nlen-1; write(6,'(a,$)')crad(i:i); end do; if(nlen>0)write(6,'(a)')crad(i:i)                                                                                                                                    
 cargout=SumStr1(crad)                                                                                                                                                                                                  
 nsp=nsp+1; i=ChCount(SumStr1(crad),' ',',')+1;                                                                                                                                                                         
if(len(cargout)<nlen)then                                                                                                                                                                                               
 call ErrorMsg(SumStr1(crad)// " is too long!",-1)                                                                                                                                                                      
!elseif(i/=nsp.and.nlen>=0)then                                                                                                                                                                                         
! call ErrorMsg(SumStr1(crad)// " has unrecognizable data number!",-1)                                                                                                                                                  
end if                                                                                                                                                                                                                  
end subroutine lineread                                                                                                                                                                                                 
于 2013-09-23T09:39:43.750 回答
0

我正在使用 Fortran 90 来执行此操作:

X = Len_Trim( Seq(I) )           ! length of individual sequence
write(*,'(a<X>)') Seq(I)(1:X)

您可以简单地将 Seq 声明为一个大字符串,然后在写出它时对其进行修剪。我不知道这个解决方案有多洁净,但它确实适用于我的目的。我知道有些编译器不支持“可变格式表达式”,但是有各种变通方法几乎可以简单地做同样的事情。

GNU Fortran 变量表达式解决方法。

于 2015-12-01T18:17:32.643 回答