首页 > 解决方案 > 具有不同行格式的 FORTRAN 解析文件

问题描述

我对 FORTRAN 的经验有限,我需要解析具有类似于以下结构的文件:

H    s         13.010000     0.019685
                1.962000     0.137977
                0.444600     0.478148

     s          0.122000     1.000000

     p          0.727000     1.000000
***
He   s         38.360000     0.023809
                5.770000     0.154891
                1.240000     0.469987

     s          0.297600     1.000000

     p          1.275000     1.000000
***

我需要搜索标签(例如He),然后将相应的块读入数组。

我知道我可以通过指定每行应该具有的格式来解析文件,但是这里有不同的格式可能。在 Python 中,我只会用空格分割每一行,并根据列数进行处理。但是如何在 FORTRAN 中解决这个问题?

标签: fortran

解决方案


您可以将每一行读取为字符串,然后对其进行处理。如果看起来格式是固定的(前两个字符中的元素符号,第六个字符中的轨道字母等),以下程序可以为您提供启发:

program elms

  implicit none

  integer, parameter :: MAX_LEN = 40
  character(len=MAX_LEN) :: line_el, line
  integer :: u
  integer :: is
  integer :: nlin
  character(len=2) :: element = 'He'

  integer, parameter :: MAX_LINES = 20
  real, dimension(MAX_LINES) :: e, f

  open(newunit=u, file='elms.dat', status='old', action='read')

  main_loop: do

     ! Read line
     read(u, '(a)', iostat=is) line_el

     if (eof_iostat(is)) exit main_loop

     ! Check first two characters of the line vs. chemical element.
     if (line_el(1:2) .eq. element) then

       ! This is the beginning of an element block
       nlin = 0
       line = line_el

       do

          if (line .ne. '') then
             ! Line is not empty or only spaces.

             nlin = nlin + 1

             if (line(6:6) .ne. ' ') then
                ! Line contains an orbital letter - process it.
             end if

             ! Read the real values in the rest of the line
             read(line(7:),*) e(nlin), f(nlin)

          end if

          ! Read next line
          read(u, '(a)', iostat=is) line

          if (eof_iostat(is)) exit main_loop

          if (line(1:2) .ne. '  ') then

             ! Finished processing element block.
             exit main_loop

          end if

       end do

     end if

  end do main_loop

  ! Close file
  close(u)

contains

  logical function eof_iostat(istat)

     ! Returns true if the end of file has been reached

     use, intrinsic :: iso_fortran_env, only: IOSTAT_END
     implicit none
     integer, intent(in) :: istat

     select case (istat)
        case (0)          ! No error
           eof_iostat = .false.
        case (IOSTAT_END) ! End of file reached
           eof_iostat = .true.
        case default      ! Error
           STOP
     end select

  end function eof_iostat

end program

您可能需要使程序成为子程序,进行element虚拟intent(in)参数,处理轨道符号等。

请注意,如果可能,一次性从文件中读取所有数据会更容易,然后在内存中搜索相关数据(例如,具有带有化学符号的数组)。


推荐阅读