15

私は、ファイルから文字入力を読み取り、(最初に)それを再び吐き出すだけのFortran95プログラムを作成するという任務を負っています。トリッキーな部分は、これらの入力行の長さが変化し(最大長が指定されていない)、ファイル内に任意の数の行が存在する可能性があることです。

私は使用しました

    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文字しかないDNAの文字列があるとします。プログラムが存在するものを読み取るだけで、追加の空白をすべて含める必要がない方法はありますか?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 文字分 (バッファの長さ) を読み取ります。ファイル位置は、一連の 1 つ以上の非進行読み取りによってレコード全体が読み取られると、次のレコード (次の行) にのみ進行します。

ファイルの終わりの条件がなければ、変数はread ステートメントが実行されるたびsizeに実際に読み取られる文字数で定義されます。buffer

EORandおよび 指定子は、ENDそれぞれレコードの終わりまたはファイルの終わりの条件が発生したときに実行フローを制御するために使用されます (実行は適切にラベル付けされたステートメントにジャンプします)。指定子を使用してこれらの条件を検出することもできますIOSTATが、2 つの条件に使用する特定の負の値はプロセッサによって異なります。

特定のレコード内で合計sizeして、その特定のレコードの長さを計算できます。

ファイルの終わりとレコードの終わりを適切に検出するループでこのような非進行読み取りをラップすると、インクリメンタル読み取り部分が得られます。

Fortran 95 では、ローカル文字変数の長さ指定は指定式でなければなりません。これは基本的に、変数の宣言を含むスコープの最初の実行ステートメントの前に安全に評価できる式です。定数は最も単純なケースを表しますが、プロシージャ内の指定式には、そのプロシージャの仮引数などを含めることができます。

任意の長さのレコード全体を読み取ることは、多段階のプロセスです。

  • 一連のインクリメンタル読み取りを使用して、現在のレコードの長さを決定します。特定のレコードに対するこれらのインクリメンタル読み取りは、レコードの終了条件が発生したときに終了します。この時点で、ファイル位置は次のレコードに移動します。
  • Backspaceファイルを対象のレコードに戻します。
  • 現在のレコードの長さを仮引数として渡して、プロシージャを呼び出します。そのプロシージャー内には、長さが仮引数によって指定される文字変数があります。
  • その呼び出されたプロシージャ内で、通常の進行入力を使用して現在のレコードをその文字変数に読み込みます。
  • その文字変数に対してさらに処理を実行してください!

各レコードは最終的に 2 回読み取られることに注意してください。1 回目はその長さを決定するため、2 回目は実際にデータを正しく「長さ」の文字変数に読み取るためです。

長さ 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 に答える