我的任务是编写一个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
的情况下完成,因为它不能在声明语句中引用吗?
答案 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
的实际字符数。
当记录结束或文件结束条件分别发生时,EOR
和END
和说明符用于控制执行流程(执行将跳转到适当标记的语句)。您还可以使用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;,但是有很多变通方法可以做同样的事情。