2

我有很多这种格式的文本文件

....
<snip>
'FOP' 0.19 1 24 1 25 7 8  /
'FOP' 0.18 1 24 1 25 9 11 /
/ 

TURX
560231
300244
70029
200250
645257
800191
900333
600334
770291
300335
220287
110262 /

SUBTRACT
'TURX' 'TURY'/
</snip>
......

我剪下的部分包含各种格式的其他各种数据。文件格式不一致(机器生成),唯一可以确定的是关键字 TURX 可能出现多次。如果它单独出现在一行上,那么接下来的几行将包含我需要提取到数组中的数字。最后一个数字将有一个空格,然后是一个正斜杠 (/)。然后我可以在之后的其他操作中使用这个数组。

如何在 fortran 中“搜索”或解析未知格式的文件,以及如何获得一个循环来获取其余数据?我对此真的很陌生,我必须使用fortran。谢谢。

4

3 回答 3

4

Fortran 95 / 2003 有很多字符串和文件处理功能,使这更容易。

例如,此代码片段用于处理未知长度的文件:

   use iso_fortran_env


  character (len=100) :: line
   integer :: ReadCode


ReadLoop: do
  read (75, '(A)', iostat=ReadCode )  line

  if ( ReadCode /= 0 ) then
     if ( ReadCode == iostat_end ) then
        exit ReadLoop
     else
        write ( *, '( / "Error reading file: ", I0 )' )  ReadCode
        stop
     end if
  end if

  ! code to process the line ....

end do ReadLoop

然后“处理行”代码可以包含几个部分,具体取决于逻辑变量“Have_TURX”。如果 Have_TRUX 为假,您正在“寻找”...测试该行是否包含“TURX”。如果 TURX 始终位于字符串的开头,则可以使用普通的“==”,或者为了更通用,您可以使用内部函数“index”来测试字符串“line”是否包含 TURX。

一旦程序处于模式 Have_TRUX 为真,然后您使用“内部 I/O”从字符串中读取数值。由于整数具有不同的长度并且左对齐,因此最简单的方法是使用“列表导向 I/O”:结合这些:

read (line, *) integer_variable

然后您可以再次使用内部函数“index”来测试字符串是否还包含斜杠,在这种情况下,您将 Have_TRUX 更改为 false 并结束阅读模式。

如果您需要将数字放入数组中,则可能需要读取文件两次,或者退格文件,因为您必须分配数组,并且在您知道数组的大小之前无法执行此操作大批。或者你可以将数字弹出到一个链表中,然后当你点击斜线时分配数组并从链表中填充它。或者,如果已知最大数量的值,您可以使用临时数组,然后将这些数字传输到可分配的输出数组。这是假设您希望子例程的输出参数是正确长度的可分配数组,并且每次调用返回一组数字:

integer, dimension (:), allocatable, intent (out) :: numbers
allocate (numbers (1: HowMany) )

PS 在http://en.wikipedia.org/wiki/Fortran_95_language_features有语言特性的简要总结,gfortran 手册有内在过程的总结,从中您可以看到哪些内置函数可用于字符串处理.

于 2011-06-07T06:23:47.127 回答
1

这是我最后的解决方法。

PROGRAM fetchnumbers
    implicit none
    character (len=50) ::line, numdata
    logical ::is_numeric        
    integer ::I,iost,iost2,counter=0,number
    integer, parameter :: long = selected_int_kind(10)
    integer, dimension(1000)::numbers !Can the number of numbers be up to 1000?

    open(20,file='inputfile.txt') !assuming file is in the same location as program
    ReadLoop: do
        read(20,*,iostat=iost) line !read data line by line
        if (iost .LT. 0) exit !end of file reached before TURX was found
        if (len_trim(line)==0) cycle ReadLoop !ignore empty lines
        if (index(line, 'TURX').EQ.1) then !prepare to begin capturing
            GetNumbers: do
                read(20, *,iostat=iost2)numdata !read in the numbers one by one
                if (.NOT.is_numeric(numdata)) exit !no more numbers to read             
                if (iost2 .LT. 0) exit !end of file reached while fetching numbers
                read (numdata,*) number !read string value into a number
                counter = counter + 1
                Storeloop: do I =1,counter
                    if (I<counter) cycle StoreLoop
                    numbers(counter)=number !storing data into array
                end do StoreLoop
            end do GetNumbers
        end if
    end do ReadLoop

    write(*,*) "Numbers are:"
    do I=1,counter
      write(*,'(I14)') numbers(I)
    end do

END PROGRAM fetchnumbers

FUNCTION is_numeric(string)
  IMPLICIT NONE
  CHARACTER(len=*), INTENT(IN) :: string
  LOGICAL :: is_numeric
  REAL :: x
  INTEGER :: e
  is_numeric = .FALSE.
  READ(string,*,IOSTAT=e) x
  IF (e == 0) is_numeric = .TRUE.
END FUNCTION is_numeric
于 2011-06-09T20:21:51.477 回答
1

我会给你一个正确的方向,这样你就可以完成你的项目。

一些基础知识:

  • Do/While因为您需要某种循环结构来循环遍历文件,然后遍历数字。Fortran 中没有 for 循环,所以使用这种类型。

  • 阅读 以阅读字符串。

要开始你需要这样的东西:

  program readlines
  implicit none
  character (len=30) :: rdline
  integer,dimension(1000) :: array
  !  This sets up a character array with 30 positions and an integer array with 1000
  !
  open(18,file='fileread.txt')
  do
     read(18,*) rdline
     if (trim(rdline).eq.'TURX') exit  !loop until the trimmed off portion matches TURX
  end do

有关将字符串转换为整数的方法,请参见此线程

最终编辑:看起来 MSB 已经掌握了我刚刚发现的大部分内容。read的iostat论点是它的关键。请参阅此站点以获取示例程序。

于 2011-06-07T02:57:32.440 回答