2

私はすでに同様の投稿をチェックしました。解決策はここでMSBによって与えられます行数はわかっているが各行のエントリ数が不明なFortranのデータファイルの読み取り

だから、私が抱えている問題は、テキストファイルから入力を読み取ろうとしているということです。1 行に 3 つの変数があるはずです。ただし、入力ファイルに 2 つの変数が含まれる場合があります。その場合、最後の変数をゼロにする必要があります。IOSTAT で READ ステートメントを使用しようとしましたが、値が 2 つしかない場合は、次の行に移動し、次に使用可能な値を読み取ります。3番目の値がない場合、2つの値を読み取った後、1行目で停止させる必要があります。

それを行う1つの方法は、IOSTAT> 0になるコメント/読み込もうとしているタイプ以外のタイプ(この場合、コメントがcharであるときにfloatを読んでいる)を持つことであり、それを小切手。しかし、場合によっては、そのコメントがない場合があります。それよりも機能することを確認したい。

コードの一部

    read(15,*) x
    read(15,*,IOSTAT=ioerr) y,z,w
    if (ioerr.gt.0) then
        write(*,*)'No value was found'
        w=0.0;
        goto 409
        elseif (ioerr.eq.0) then
        write(*,*)'Value found', w
        endif
  409   read(15,*) a,b
        read(15,*) c,d

INPUT FILE の形式は次のとおりです。

    -1.000  abcd                                                                        
    12.460  28.000  8.00 efg                                                                            
    5.000   5.000   hijk                                                                            
    20.000  21.000  lmno                                                                            

「8.00 efg」がない場合でも機能させる必要があります

この場合

    -1.000  abcd                                                                        
     12.460 28.000                                                                              
     5.000  5.000   hijk                                                                            
     20.000 21.000  lmno

MSB が提案する文字列メソッドを使用できません。他に方法はありますか?

4

5 に答える 5

0

Fortran 90 のソリューションで問題ない場合は、次の手順を使用して、複数の実数値を含む行を解析できます。

subroutine readnext_r1(string, pos, value)
  implicit none
  character(len=*), intent(in)    :: string
  integer,          intent(inout) :: pos
  real,             intent(out)   :: value

  integer                         :: i1, i2

  i2 = len_trim(string)

  ! initial values:
  if (pos > i2) then
     pos   = 0
     value = 0.0
     return
  end if

  ! skip blanks:
  i1 = pos
  do
     if (string(i1:i1) /= ' ') exit
     i1 = i1 + 1
  end do

  ! read real value and set pos:
  read(string(i1:i2), *) value
  pos = scan(string(i1:i2), ' ')
  if (pos == 0) then
     pos = i2 + 1
  else
     pos = pos + i1 - 1
  end if

end subroutine readnext_r1

サブルーチンは文字列 'string' から文字番号 'pos' で始まる次の実数を読み取り、'value' に値を返します。文字列の末尾に達した場合、'pos' はゼロに設定され (値 0.0 が返されます)、それ以外の場合は、読み取った実数の後ろの文字位置まで 'pos' がインクリメントされます。

したがって、あなたの場合、最初に行を文字列に読み取ります。

character(len=1024) :: line
...
read(15,'(A)') line
...

次に、この文字列を解析します

real    :: y, z, w
integer :: pos
...
pos = 1
call readnext_r1(line, pos, y)
call readnext_r1(line, pos, z)
call readnext_r1(line, pos, w)
if (pos == 0) w = 0.0

最後の「if」は必要ありません(ただし、この方法ではより透過的です)。

行に実数ではない 3 番目のエントリがある場合、この手法は失敗することに注意してください。

于 2012-04-11T08:30:42.307 に答える
0

行の実数を数えるルーチンがあります。これをあなたの目的にかなり簡単に適応させることができると思います。

subroutine line_num_columns(iu,N,count)
    implicit none

    integer(4),intent(in)::iu,N

    character(len=N)::line
    real(8),allocatable::r(:)
    integer(4)::r_size,count,i,j

    count=0 !Set to zero in case of premature return

    r_size=N/5 !Initially try out this max number of reals
    allocate(r(r_size))

    read(iu,'(a)') line

50  continue
    do i=1,r_size
        read(line,*,end=99) (r(j),j=1,i) !Try reading i reals
        count=i
        !write(*,*) count
    enddo
    r_size=r_size*2 !Need more reals
    deallocate(r)
    allocate(r(r_size))
    goto 50

    return

99  continue
    write(*,*) 'I conclude that there are ',count,' reals on the first line'


end subroutine line_num_columns
于 2012-04-11T04:53:39.973 に答える
0

すばらしい名前のコロン編集記述子を使用できる場合があります。これにより、I/O リストにそれ以上項目がない場合、フォーマットの残りをスキップできます。

Program test

  Implicit None

  Real :: a, b, c
  Character( Len = 10 ) :: comment


  Do

     c = 0.0
     comment = 'No comment'
     Read( *, '( 2( f7.3, 1x ), :, f7.3, a )' ) a, b, c, comment

     Write( *, * ) 'I read ', a, b, c, comment

  End Do

End Program test

たとえば、gfortran を使用すると、次のようになります。

Wot now? gfortran -W -Wall -pedantic -std=f95 col.f90
Wot now? ./a.out
  12.460  28.000  8.00 efg
 I read    12.460000       28.000000       8.0000000     efg       
  12.460  28.000  
 I read    12.460000       28.000000      0.00000000E+00           
^C

これは、gfortran、g95、NAG コンパイラ、Intel のコンパイラ、および Sun/Oracle コンパイラで動作します。ただし、これを理解していると完全に確信しているわけではありません.cまたはコメントが読み取られない場合、それらはそれぞれ0とすべてのスペースであることが保証されますか? よくわからないので、他の場所で尋ねる必要があります。

于 2012-04-11T13:58:09.957 に答える
0

過去に似たようなことをしようとしたことを覚えているようです。ファイルの行のサイズが特定の数を超えないことがわかっている場合は、次のようなことを試すことができる場合があります。

...
character*(128) A  

read(15,'(A128)') A  !This now holds 1 line of text, padded on the right with spaces
read(A,*,IOSTAT=ioerror) x,y,z
if(IOSTAT.gt.0)then
   !handle error here
endif

このソリューションがあるコンパイラから次のコンパイラにどの程度移植可能かは完全にはわかりません.f77標準でそれを読む時間は今のところありません...

于 2012-04-11T01:16:42.170 に答える