读取未知长度的字符串

时间:2013-02-08 03:49:48

标签: input fortran character string-length fortran95

我的任务是编写一个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 个答案:

答案 0 :(得分:10)

要逐步读取Fortran 95中的记录,请使用非前进输入。例如:

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

最多可读取10个字符(缓冲区的长度)。一旦整个记录被一系列一个或多个非前进读取读取,文件位置将仅前进到下一个记录(下一行)。

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

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

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

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

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

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

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

请注意,每条记录最终都被读取两次 - 一次确定其长度,第二次实际将数据读入正确的“加长”字符变量。

存在使用长度为1的可分配(或自动)字符数组的替代方法。总体战略是一样的。有关示例,请查看常见ISO_VARYING_STRING实现中的Get过程的code

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

答案 1 :(得分:9)

这是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

例如,使用单位&#34; aunit&#34;对文件中的所有行执行某些操作。做

 character(LEN=:), allocatable :: InLine

 do while (ReadLine(aunit, InLine))
   [.. something with InLine]
 end do

答案 2 :(得分: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                                                                                                                                                                                                 

答案 3 :(得分:0)

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

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

您可以简单地将Seq声明为一个大字符串,然后在写出来时将其修剪。我不知道这个解决方案是多么合适,但它确实适用于我的目的。我知道有些编译器不支持&#34;变量格式表达式&#34;,但是有很多变通方法可以做同样的事情。

GNU Fortran variable expression workaround.